La validación de datos en FastAPI se realiza utilizando Pydantic, lo que permite definir reglas de validación de manera declarativa y eficaz. A continuación, exploraremos cómo implementar esta funcionalidad en FastAPI.
1. Definición de Modelos de Pydantic
En FastAPI, los modelos de Pydantic son usados para validar datos de entrada y salida. Puedes establecer tipos de datos, valores predeterminados, restricciones y más.
from pydantic import BaseModel, Field, EmailStr
class User(BaseModel):
username: str = Field(..., min_length=3, max_length=50, description="Nombre del usuario")
email: EmailStr
age: int = Field(..., gt=0, le=120, description="Edad del usuario, debe ser entre 1 y 120 años")
2. Validación Automática en Endpoints
Cuando defines un endpoint con un modelo de Pydantic como parámetro, FastAPI valida automáticamente los datos recibidos.
from fastapi import FastAPI, HTTPException
app = FastAPI()
@app.post("/users/")
async def create_user(user: User):
return {"message": "Usuario creado exitosamente", "user": user}
Validación en Acción
Si envías datos que no cumplen con las reglas definidas (por ejemplo, un correo no válido o un nombre muy corto), FastAPI responderá con un error 422 y detalles sobre la validación.
3. Uso de Validaciones Personalizadas
Puedes definir validaciones adicionales utilizando métodos en el modelo de Pydantic.
Ejemplo: Validar Nombre Único
from pydantic import BaseModel, validator
class User(BaseModel):
username: str
email: EmailStr
age: int
@validator("username")
def validate_unique_username(cls, value):
if value.lower() in ["admin", "root"]:
raise ValueError("El nombre de usuario no puede ser 'admin' o 'root'")
return value
4. Validación Compleja con Dependencias
Además de usar Pydantic, puedes implementar dependencias para manejar validaciones más dinámicas.
from fastapi import Depends
def validate_age(age: int):
if age < 18:
raise HTTPException(status_code=400, detail="La edad debe ser mayor o igual a 18")
return age
@app.get("/validate/")
async def check_age(age: int = Depends(validate_age)):
return {"message": f"La edad {age} es válida"}
5. Validación en la Salida
Puedes usar modelos de Pydantic para controlar cómo se devuelven los datos al cliente.
from fastapi.responses import JSONResponse
class UserOut(BaseModel):
username: str
email: EmailStr
@app.get("/users/{user_id}", response_model=UserOut)
async def get_user(user_id: int):
user = {"username": "john_doe", "email": "john.doe@example.com", "age": 30} # Simulación
return user
En este caso, solo se devuelven username y email, aunque el objeto user contiene más datos.
6. Validación de Entradas y Salidas Juntas
Puedes usar modelos diferentes para entrada y salida si los datos requeridos son distintos.
class UserIn(BaseModel):
username: str
password: str
class UserOut(BaseModel):
username: str
email: EmailStr
@app.post("/users/", response_model=UserOut)
async def create_user(user: UserIn):
new_user = {"username": user.username, "email": "user@example.com"} # Simulación
return new_user
7. Uso de Tipos Avanzados
Puedes usar tipos avanzados como listas, diccionarios o incluso modelos anidados.
from typing import List
class Item(BaseModel):
name: str
price: float
class Order(BaseModel):
order_id: int
items: List[Item]
total_price: float
@app.post("/orders/")
async def create_order(order: Order):
return order
8. Manejo de Errores de Validación
Si necesitas personalizar el comportamiento cuando ocurre un error de validación, puedes usar los event handlers.
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse
from fastapi import Request
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request: Request, exc: RequestValidationError):
return JSONResponse(
status_code=422,
content={"detail": exc.errors(), "body": exc.body},
)
Conclusión
La validación en FastAPI con Pydantic es robusta y flexible. Permite manejar desde casos simples hasta validaciones complejas con facilidad.