Skip to content

Capítulo 3.6: Manejo de errores y validación

Tiempo de estudio: 50 minutos


1. Manejo de errores: Los "escudos de emergencia" de una nave espacial

Incluso en la nave más perfecta, pueden ocurrir situaciones imprevistas:

  • Comando incorrecto del Centro de Control: El cliente envió datos incorrectos.
  • Pérdida de conexión con el módulo: Recurso no encontrado en la base de datos.
  • Fallo en el reactor: Error interno del servidor.

El manejo adecuado de errores es un sistema de "escudos de emergencia". Evita que la nave se desintegre y, en su lugar, envía una señal clara al Centro de Control sobre lo que salió mal.

💡 Analogía espacial:

En lugar de simplemente transmitir una señal de "¡ACCIDENTE!" al Centro de Control, una buena computadora de a bordo enviará un informe estructurado:

{
  "error_code": "ENGINE_OVERHEAT",
  "message": "La temperatura del motor #2 superó la norma",
  "suggested_action": "Activar el sistema de enfriamiento"
}
Esto permite a los ingenieros en la Tierra comprender rápidamente el problema y tomar medidas.


2. Validación Pydantic: La "computadora de a bordo" integrada

Ya nos hemos encontrado con la magia de Pydantic. Si intentas crear una nave con un tipo de datos incorrecto (por ejemplo, launch_year como cadena de texto), FastAPI devolverá automáticamente un error 422 Unprocessable Entity con una descripción detallada de qué campo y por qué no pasó la validación.

Ejemplo de solicitud a POST /spaceships:

{
  "name": "X-Wing",
  "type": "Caza",
  "launch_year": "hace mucho tiempo",  // <-- ¡Tipo incorrecto!
  "status": "En servicio"
}

Respuesta automática de FastAPI:

{
  "detail": [
    {
      "loc": [
        "body",
        "launch_year"
      ],
      "msg": "el valor no es un entero válido",
      "type": "type_error.integer"
    }
  ]
}
¡Esto es increíblemente potente! No necesitas escribir código para verificar tipos: FastAPI y Pydantic lo hacen por ti.


3. Manejo de "Recurso no encontrado": Excepción HTTPException

Ya hemos utilizado esto en las operaciones CRUD. HTTPException es la forma estándar de FastAPI de interrumpir la ejecución de una solicitud y devolver inmediatamente una respuesta de error al cliente.

Recordemos el código de GET /spaceships/{ship_id}:

# main.py
from fastapi import FastAPI, HTTPException # Asegúrate de que HTTPException esté importado

# ...

@app.get("/spaceships/{ship_id}", response_model=Spaceship, tags=["Naves espaciales"])
def get_spaceship(ship_id: int):
    ship = db_spaceships.get(ship_id)
    if not ship:
        # Si la nave no se encuentra, "lanzamos" una excepción 404
        raise HTTPException(status_code=404, detail=f"Nave espacial con ID {ship_id} no encontrada")
    return ship

  • raise HTTPException(...): Esta llamada detiene la ejecución de la función.
  • status_code=404: Establece el estado HTTP de la respuesta.
  • detail: Mensaje que se enviará al cliente en el cuerpo de la respuesta JSON.

4. Validadores personalizados: "Verificaciones especiales" antes del lanzamiento

¿Qué pasa si queremos añadir nuestra propia lógica de negocio más compleja? Por ejemplo, prohibir el lanzamiento de naves con el nombre "Estrella de la Muerte".

Para ello, Pydantic cuenta con una poderosa herramienta: los validadores.

Paso 1: Añadir un validador al modelo SpaceshipCreate

# main.py
from pydantic import BaseModel, Field, validator

class SpaceshipCreate(BaseModel):
    name: str = Field(..., min_length=3, max_length=50)
    type: str
    launch_year: int = Field(..., gt=1950)
    status: str

    @validator('name')
    def name_must_not_be_forbidden(cls, v):
        """Verifica que el nombre de la nave no esté en la lista de nombres prohibidos."""
        if 'Death Star' in v:
            raise ValueError('¡Nombres como "Estrella de la Muerte" están prohibidos por decreto imperial!')
        return v.title() # De paso, ponemos la primera letra del nombre en mayúscula

  • @validator('name'): Un decorador que "vincula" esta función al campo name.
  • cls, v: El método recibe la clase misma (cls) y el valor del campo (v).
  • raise ValueError(...): Si la validación falla, lanzamos una excepción estándar de Python. FastAPI la interceptará y la convertirá en un bonito error 422.
  • return v.title(): Si todo está bien, debemos devolver el valor obligatoriamente. Incluso podemos modificarlo sobre la marcha (por ejemplo, convertirlo a un formato estándar).

Paso 2: Probar Reinicia uvicorn e intenta crear una nave con un nombre prohibido a través de /docs. ¡Recibirás un error 422 con tu mensaje personalizado!


5. Manejo global de errores: El "protocolo de emergencia" de la estación

A veces es necesario interceptar errores inesperados (por ejemplo, un fallo de conexión a una base de datos real) y devolver un formato de respuesta único y estandarizado.

Para ello se utiliza el decorador @app.exception_handler.

Ejemplo: Interceptación de todos los errores ValueError

# main.py
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse

# ...

@app.exception_handler(ValueError)
async def value_error_exception_handler(request: Request, exc: ValueError):
    """
    Manejador global para todos los errores ValueError,
    para devolver un JSON estandarizado.
    """
    return JSONResponse(
        status_code=400,
        content={"message": f"Error en los datos: {str(exc)}"},
    )

  • @app.exception_handler(ValueError): Le dice a FastAPI que esta función debe manejar todos los ValueError que no hayan sido interceptados previamente.
  • async def ...: Los manejadores de excepciones deben ser asíncronos (async).
  • JSONResponse: Permite un control total sobre el cuerpo y el estado de la respuesta.

Ahora, cuando nuestro validador personalizado se active, la respuesta tendrá un formato más amigable que el que hemos definido.


Cuestionario de repaso

1. Si el cliente envía datos de un tipo incorrecto (una cadena en lugar de un número), FastAPI devolverá automáticamente el estado...

2. `raise HTTPException(status_code=404)` se utiliza para...

3. El decorador `@validator('field_name')` en Pydantic es necesario para:

4. ¿Qué debe hacer una función validadora en Pydantic si los datos son correctos?

5. `@app.exception_handler()` permite...


🚀 Resumen del capítulo:

Ha instalado en su nave API un potente sistema de seguridad y protocolos de emergencia. Ahora puede:

  • 🛡️ Repeler automáticamente los ataques de "datos incorrectos" utilizando Pydantic.
  • 🚨 Informar correctamente sobre la ausencia de recursos (404 Not Found) a través de HTTPException.
  • ⚙️ Realizar "validaciones especiales" utilizando validadores personalizados.
  • 🧯 Interceptar globalmente fallos inesperados y proporcionar respuestas estandarizadas.

¡Su "hiperimpulsor" no solo es rápido, sino también increíblemente fiable!

📌 Verificación:

  • Intente crear una nave con el nombre "Death Star" y asegúrese de recibir un error 400 con su mensaje personalizado.
  • Intente solicitar GET /spaceships/999 y asegúrese de recibir un error 404.
  • Intente enviar una solicitud POST con launch_year como una cadena de texto y asegúrese de recibir un error 422.

⚠️ Si hay errores:

  • Asegúrese de que todos los módulos necesarios (HTTPException, validator, Request, JSONResponse) estén importados.
  • Verifique que los decoradores @validator y @app.exception_handler estén escritos sin errores tipográficos.

¡Enhorabuena por completar el Capítulo 3! Ha construido y lanzado desde cero una API potente, documentada y protegida con FastAPI. Está listo para emprender auténticas misiones espaciales.