Curso Python: Validaciones con Pydantic

desarrollo de aplicaciones web

Este artículo es una continuación de nuestro curso sobre la creación de API con FastAPI. Si deseas explorar la estructura completa del curso y profundizar aún más en este apasionante mundo, haz click aquí.

Además, podría interesarte leer este otro artículo, en el que explico cómo descargar e instalar Python, así como las librerías y dependencias necesarias para seguir este curso de manera efectiva.

¿Qué es Pydantic?

Pydantic es una biblioteca de validación de datos y gestión de configuraciones para Python que se basa en las anotaciones de tipos de Python para validar automáticamente los datos. Está diseñada para ser rápida y sencilla de usar, ofreciendo una forma robusta de manejar datos inmutables en tu código. Aquí te explico algunas de sus características y usos principales

Características principales

  1. Validación Fuerte de Tipos: Utiliza anotaciones de tipo estándar de Python para validar datos, asegurando que los datos recibidos coincidan con los tipos esperados y cumpliendo automáticamente las conversiones de tipo cuando sea posible.
  2. Errores Descriptivos: Cuando los datos no cumplen con el esquema definido, Pydantic genera errores detallados que indican exactamente qué campo falló y por qué, lo que facilita la depuración.
  3. Soporte para Modelos Personalizados: Puedes definir tus propios modelos utilizando la clase BaseModel de Pydantic, especificando los tipos de datos, validaciones adicionales, y valores predeterminados.
  4. Integración con Sistemas Externos: Pydantic puede ser usado para validar datos que provienen de fuentes externas, como APIs, archivos de configuración o formularios de usuario, haciendo que la integración de estos datos en tu aplicación sea más segura y fácil.
  5. Extensibilidad: Permite la creación de validadores personalizados en caso de que necesites una lógica de validación que no se incluya por defecto.
  6. Integración con ORM: Pydantic puede ser integrado con ORMs como SQLAlchemy para asegurar que los datos que entran y salen de la base de datos sean correctos.
  7. Generación de Esquemas: Puede generar automáticamente esquemas JSON de tus modelos, lo cual es útil para documentación y generación de interfaces de usuario automáticas, como las que se utilizan en FastAPI.

Uso Común con FastAPI

En combinación con FastAPI, Pydantic es particularmente potente. FastAPI utiliza modelos Pydantic para definir los datos esperados en las peticiones y las respuestas de tu API. Esto no solo ayuda con la validación y documentación automática (a través de OpenAPI), sino que también facilita el desarrollo al garantizar que los datos que maneja tu aplicación estén bien formados y sean predecibles.

Para evolucionar la API de libros que mencionaste al inicio, se puede proceder por etapas, cada una agregando funcionalidades y robustez al proyecto. Aquí te muestro cómo podrías organizar el desarrollo:

Etapa 1: Creación de Esquemas con Pydantic

El primer paso consiste en definir modelos claros y robustos usando Pydantic, lo cual ayudará a garantizar que los datos recibidos y enviados a través de la API sean válidos y estén bien estructurados.

  • Definir Modelos de Datos: Utiliza BaseModel de Pydantic para crear clases que representen los esquemas de datos, como el modelo Book ya definido. Aquí puedes expandir los esquemas para incluir más detalles, relaciones o sub-modelos según las necesidades de tu aplicación.
  • Especificar Atributos y Tipos de Datos: Define tipos explícitos para cada atributo en tus modelos, y usa anotaciones de tipo para todo, desde tipos primitivos hasta listas y modelos más complejos.
from pydantic import BaseModel, Field, validator
from datetime import date
from typing import Optional

class Book(BaseModel):
    id: Optional[int] = None
    title: str = Field(…, example="Clean Code", description="El título del libro")
    category: str = Field(…, example="programación", description="La categoría del libro")
    date: date = Field(…, example="2020-04-05", description="Fecha de publicación del libro")

@validator('date')
def validate_date(cls, v):
    if v > date.today():
        raise ValueError("La fecha no puede ser en el futuro")
    return v

Etapa 2: Validaciones de Tipos de Datos con Pydantic

Con los esquemas establecidos, el siguiente paso es implementar validaciones que garantizan la integridad de los datos recibidos según esos esquemas.

  • Personalizar Validaciones: Más allá de las validaciones automáticas proporcionadas por Pydantic, define validaciones personalizadas utilizando validator para campos específicos que necesiten reglas de negocio particulares, como formatos de fecha específicos o rangos de valores.
  • Validación Automática en Entradas: Asegúrate de que FastAPI utilice los modelos Pydantic para validar automáticamente todos los datos de entrada en las rutas de la API.

Etapa 3: Validaciones de Parámetros con Pydantic

Esta etapa implica asegurarse de que todos los parámetros que pasan a través de la API, tanto en las rutas como en las consultas, se validen adecuadamente.

  • Parámetros de Ruta y Consulta: Utiliza modelos Pydantic o tipos específicos para validar parámetros de ruta (path parameters) y parámetros de consulta (query parameters).
  • Opciones Avanzadas de Validación: Implementa opciones más complejas como parámetros opcionales, valores predeterminados, y restricciones de longitud o rango.

from fastapi import Query

@app.get("/books/", tags=['books'])
def get_books_by_category(category: str = Query(…, example="programación", description="Filtra libros por categoría")):
    books_category = [book for book in books if book["category"] == category]
    return books_category

Etapa 4: JSONResponse: Tipos de Respuestas en FastAPI

Implementa diferentes tipos de respuestas para mejorar la comunicación de la API con los clientes.

  • Respuestas Estándar y Personalizadas: Utiliza JSONResponse para enviar respuestas JSON estandarizadas. Personaliza estas respuestas para incluir más metadatos o para manejar estructuras de datos específicas.
  • Manejo de Errores: Define respuestas para diferentes escenarios de error, utilizando diferentes tipos de respuesta como HTTPException o respuestas personalizadas que informen claramente del error al cliente.
from fastapi.responses import JSONResponse

@app.get("/books/{id}", tags=['books'])
def get_book(id: int):
    for book in books:
        if book["id"] == id:
           return JSONResponse(status_code=200, content={"success": True, "book": book})
    return JSONResponse(status_code=404, content={"success": False, "message": "Libro no encontrado"})

Etapa 5: Códigos de Estado HTTP en FastAPI

La última etapa consiste en utilizar adecuadamente los códigos de estado HTTP para comunicar el resultado de las operaciones de la API de manera más semántica y útil.

  • Éxito y Error: Asegúrate de que cada operación de la API devuelva el código de estado adecuado (como 200 OK, 201 Created, 404 Not Found, 400 Bad Request) dependiendo del resultado de la operación.
  • Documentación y Consistencia: Documenta los códigos de estado que cada endpoint puede retornar para ayudar a los desarrolladores que consumen tu API a entender mejor qué esperar.
from fastapi import HTTPException

@app.post("/books/", tags=['books'])
def create_book(book: Book):
    new_book = book.dict()
    new_book['id'] = max(b['id'] for b in books) + 1 if books else 1
    books.append(new_book)
    return JSONResponse(status_code=201, content={"success": True, "id": new_book['id']})

@app.delete("/books/{id}", tags=['books'])
def delete_book(id: int):
    for book in books:
        if book["id"] == id:
           books.remove(book)
           return JSONResponse(status_code=204, content={})
    raise HTTPException(status_code=404, detail="Libro no encontrado")

Al seguir estas etapas, tu API de libros no solo será funcional sino también robusta, segura y fácil de usar para otros desarrolladores.

Aquí te dejo el enlace al repo del código

Un comentario

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *