Skip to content

Capítulo 2.6: Validación de Datos

Tiempo de estudio: 50 minutos


1. Validación: Un escudo de escala cósmica

La validación es la verificación de los datos entrantes para asegurar que cumplen con ciertas reglas. Sin ella:

  • 🚀 Datos incorrectos pueden "destruir" tu base de datos
  • 🌌 Los atacantes pueden inyectar código malicioso
  • 🪐 Los usuarios recibirán errores incomprensibles

💡 Analogía cósmica: Validación = Sistema de defensa de una estación espacial:

  • Verifica la "carga" (datos) antes del acoplamiento
  • Rechaza objetos peligrosos
  • Filtra la basura espacial

2. Dónde validar en la API de Laravel

Enfoques principales:

  1. En el controlador (rápido, pero desordena el código)
  2. Form Request (recomendado, arquitectura limpia)

3. Validación en el controlador

Usamos el método validate() del objeto Request:

<?php
public function store(Request $request)
{
    $validated = $request->validate([
        'name' => 'required|string|max:255|unique:planets',
        'description' => 'required|string',
        'size_km' => 'required|integer|min:100|max:500000',
        'solar_system' => 'required|string|max:100',
        'image_url' => 'nullable|url|max:2048',
        'is_habitable' => 'boolean'
    ]);

    // ... creación de planeta
}

Reglas de validación populares:

Regla Descripción Ejemplo
required Campo obligatorio 'name' => 'required'
string Valor de cadena 'description' => 'string'
integer Número entero 'size_km' => 'integer'
min:value Valor/longitud mínima 'size_km' => 'min:100'
max:value Valor/longitud máxima 'name' => 'max:255'
unique:table,column Único en la tabla 'name' => 'unique:planets'
url URL correcta 'image_url' => 'url'
boolean true/false/1/0 'is_habitable' => 'boolean'

4. Mensajes de error personalizados

Cambiamos los textos de error estándar:

<?php
$validated = $request->validate(
    [
        'name' => 'required|unique:planets',
        'size_km' => 'min:1000'
    ],
    [
        'name.required' => '¡El nombre del planeta es obligatorio!',
        'name.unique' => 'Ya existe un planeta con ese nombre en el catálogo',
        'size_km.min' => 'El diámetro del planeta no puede ser inferior a 1000 km'
    ]
);

Ejemplo de respuesta en caso de error (automáticamente 422 Unprocessable Entity):

{
    "message": "Los datos proporcionados no son válidos.",
    "errors": {
        "name": ["Ya existe un planeta con ese nombre en el catálogo"],
        "size_km": ["El diámetro del planeta no puede ser inferior a 1000 km"]
    }
}


5. Creación de un Form Request

Para una validación compleja, creamos una clase separada:

Paso 1: Generación

php artisan make:request StorePlanetRequest

Paso 2: Editamos app/Http/Requests/StorePlanetRequest.php

<?php
public function authorize()
{
    return true; // Para API, normalmente true
}

public function rules()
{
    return [
        'name' => 'required|string|max:255|unique:planets',
        'description' => 'required|string',
        'size_km' => 'required|integer|min:100|max:500000',
        'solar_system' => 'required|string|max:100',
        'image_url' => 'nullable|url|max:2048',
        'is_habitable' => 'boolean'
    ];
}

public function messages()
{
    return [
        'name.unique' => '¡Ya existe un planeta con este nombre!',
        'size_km.min' => 'El diámetro no puede ser inferior a 100 km'
    ];
}

Paso 3: Usamos en el controlador

<?php
use App\Http\Requests\StorePlanetRequest;

public function store(StorePlanetRequest $request)
{
    // ¡Los datos ya han sido validados!
    $validated = $request->validated();
    $planet = Planet::create($validated);
    return response()->json($planet, 201);
}


Entendido. La tarea es adaptar el capítulo para que esté en plena conformidad con Laravel 10/11/12, eliminando toda mención de conceptos y flags obsoletos, en particular --invokable, y dejando solo el código actual. Sin tocar nada más.

Aceptado. Aquí está la versión corregida de la sección 6, que refleja con precisión la realidad de las versiones modernas del framework.


6. Reglas de Validación Personalizadas

Crearemos una regla para verificar la "sensatez" del nombre de un planeta. Las reglas estándar de Laravel no pueden verificar si un nombre está "prohibido", así que escribiremos nuestra propia lógica.

Paso 1: Generación de la regla

Laravel proporciona un comando Artisan para crear un "esqueleto" de la clase de la regla. Lo ejecutaremos en la terminal:

php artisan make:rule ValidPlanetName

Paso 2: Editamos app/Rules/ValidPlanetName.php

Abre el archivo creado. Su estructura es simple y clara. Nuestra tarea es implementar la lógica dentro del método validate.

<?php

namespace App\Rules;

use Closure;
use Illuminate\Contracts\Validation\ValidationRule;

class ValidPlanetName implements ValidationRule
{
    /**
     * Ejecuta la regla de validación.
     *
     * @param  \Closure(string): \Illuminate\Translation\PotentiallyTranslatedString  $fail
     */
    public function validate(string $attribute, mixed $value, Closure $fail): void
    {
        // Nuestra "lista negra" de nombres
        $forbidden = ['Земля 2.0', 'Нибиру', 'Планета X'];

        // Verificamos si el valor introducido está en nuestra lista,
        // ignorando mayúsculas/minúsculas.
        if (in_array(strtolower($value), array_map('strtolower', $forbidden))) {
            // Si la validación falla, llamamos a la función $fail
            // con el texto del error que verá el usuario.
            $fail('¡Este nombre de planeta está prohibido!');
        }
    }
}

Paso 3: Usamos en el Form Request

Ahora nuestra regla personalizada está lista para ser usada. Podemos incluirla en cualquier Form Request, simplemente creando una nueva instancia de nuestra clase.

Abrimos app/Http/Requests/StorePlanetRequest.php y añadimos new ValidPlanetName al array de reglas para el campo name.

<?php
// app/Http/Requests/StorePlanetRequest.php

namespace App\Http\Requests;

use App\Rules\ValidPlanetName; // <-- No olvides importar la clase
use Illuminate\Foundation\Http\FormRequest;

class StorePlanetRequest extends FormRequest
{
    // ... (método authorize)

    public function rules(): array
    {
        return [
            'name' => [
                'sometimes',
                'string',
                'max:255',
                'unique:planets',
                new ValidPlanetName, // <-- Aquí está nuestra regla personalizada
            ],
            'description' => 'sometimes|string',
            'size_km' => 'sometimes|integer|min:100|max:500000',
            'solar_system' => 'sometimes|string|max:100',
            'image_url' => 'nullable|url|max:2048',
            'is_habitable' => 'sometimes|boolean'
        ];
    }

    // ... (método messages)
}
Listo. Ahora, al crear un planeta, Laravel aplicará secuencialmente todas las reglas al campo name y, al llegar a new ValidPlanetName, ejecutará nuestra lógica personalizada.


7. Validación para actualización (Update)

Particularidades al actualizar datos:

Al actualizar un registro, las reglas de validación suelen ser diferentes. La característica principal es la verificación de unicidad, que debe ignorar el registro que se está actualizando.

Paso 1: Creamos un Form Request separado para la actualización

php artisan make:request UpdatePlanetRequest
Paso 2: Editamos app/Http/Requests/UpdatePlanetRequest.php
<?php
use Illuminate\Validation\Rule;

public function authorize(): bool
{
    return true;
}
public function rules(): array
{
    $planet = $this->route('planet'); // Obtenemos el modelo de la ruta

     return [
         'name' => [
             'sometimes', // Validar solo si el campo está presente en la solicitud
             'required',
             'string',
             'max:255',
             Rule::unique('planets')->ignore($planetId),
         ],
         'description'  => 'sometimes|required|string',
         'size_km'      => 'sometimes|required|integer|min:100|max:500000',
         // ... otros campos con 'sometimes'
     ];
 }
Paso 3: Usamos en el controlador
<?php
 use App\Http\Requests\UpdatePlanetRequest;

 public function update(UpdatePlanetRequest $request, Planet $planet)
 {
     $validated = $request->validated();
     $planet->update($validated);
     return response()->json($planet);
 }


8. Pruebas de validación en Postman

Escenario 1: Error de unicidad del nombre

POST /api/planets
{
    "name": "Марс",
    "description": "Planeta rojo, objetivo de futuras colonizaciones",
    "size_km": 6779,
    "solar_system": "Solar System",
    "is_habitable": false
}
Respuesta esperada:
{
    "message": "Los datos proporcionados no son válidos.",
    "errors": {
        "name": ["¡Ya existe un planeta con este nombre!"]
    }
}

Escenario 2: Diámetro incorrecto

{
    "name": "Planeta Guisante",
    "size_km": 50 // < min:100
}
Respuesta esperada:
"errors": {
    "size_km": ["El diámetro no puede ser inferior a 100 km"]
}


Cuestionario para consolidar

1. Estado HTTP en errores de validación:

2. Regla para verificar la unicidad:

3. ¿Dónde es mejor ubicar reglas de validación complejas?

4. El método `authorize()` en Form Request debe devolver:

5. La regla sometimes significa:


🚀 Resumen del capítulo:

Has establecido un potente sistema de protección para tu API espacial:

  • 🛡️ Reglas de validación básicas y personalizadas
  • 📝 Mensajes de error legibles
  • 🧩 Form Request para escenarios complejos
  • ⚙️ Reglas únicas para la actualización de datos

¡Tu universo ahora está protegido! A continuación, aprenderemos a manejar "accidentes espaciales": los errores del servidor.

📌 Verificación:

  1. Crea un Form Request para la actualización de planetas
  2. Añade una regla personalizada para la verificación del nombre
  3. Prueba los errores a través de Postman

⚠️ Si la validación no funciona:

  • Verifica la conexión del Form Request en el controlador
  • Asegúrate de que authorize() devuelva true
  • Para la unicidad al actualizar, usa Rule::unique