Creación y Suscripción de Planes y Clientes en FastAPI

Clase 15 de 23Curso de FastAPI

Contenido del curso

Resumen

Construir una API que permita crear planes, listar planes y suscribir clientes a esos planes es una tarea fundamental cuando trabajas con modelos de negocio basados en suscripciones. A continuación se explica paso a paso cómo lograrlo usando FastAPI, SQLModel y una base de datos SQLite, cubriendo desde la creación del router hasta la validación de relaciones muchos a muchos.

¿Cómo crear el endpoint para registrar planes?

El primer paso es generar un nuevo archivo dentro de la carpeta routers llamado plans. Dentro de él se importa APIRouter desde FastAPI y se define el router [0:18].

El endpoint de creación utiliza el método POST con el path /plans. Recibe dos parámetros: plan_data de tipo Plan (importado desde los modelos) y la session de base de datos [0:30].

python @router.post("/plans") async def create_plan(plan_data: Plan, session: Session): plan_db = Plan.model_validate(plan_data.model_dump()) session.add(plan_db) session.commit() session.refresh(plan_db) return plan_db

  • model_validate recibe un diccionario con todos los campos y valida la data del usuario.
  • session.add agrega el objeto a la sesión.
  • session.commit ejecuta la transacción en la base de datos.
  • session.refresh actualiza la variable en memoria con los datos persistidos, incluyendo el ID generado.

Después de registrar el router en main.py y correr la aplicación, ya es posible probar desde los docs de FastAPI [1:06].

¿Qué hacer cuando la base de datos no refleja los cambios del modelo?

Si al ejecutar el request aparece un error indicando que un campo no existe, significa que el modelo fue modificado pero la base de datos no se regeneró [1:18]. Lo ideal es usar migraciones, pero como alternativa rápida se puede borrar la base de datos y reiniciar la aplicación para que se recreen las tablas con el schema actualizado [1:36].

Para verificar, se puede inspeccionar el schema de la tabla plan directamente en la terminal y confirmar que los nuevos campos ya existen [1:52].

¿Cómo suscribir un customer a un plan específico?

Con los planes creados (por ejemplo, premium con precio 1000 y basic con precio 100), el siguiente objetivo es construir un endpoint que relacione un customer con un plan [2:22].

Este endpoint se coloca en el router de customers porque la URL sigue una ruta anidada: /customers/{customer_id}/plans/{plan_id} [2:40].

python @router.post("/customers/{customer_id}/plans/{plan_id}") async def subscribe_customer_to_plan(customer_id: int, plan_id: int, session: Session): customer_db = session.get(Customer, customer_id) plan_db = session.get(Plan, plan_id)

if not customer_db or not plan_db: raise HTTPException(status_code=404, detail="The customer or plan doesn't exist") customer_plan_db = CustomerPlan(plan_id=plan_db.id, customer_id=customer_db.id) session.add(customer_plan_db) session.commit() session.refresh(customer_plan_db) return customer_plan_db
  • Se obtienen ambos objetos con session.get [2:55].
  • Se valida que existan; si alguno no se encuentra, se lanza una HTTPException con código 404 [3:10].
  • La relación se crea instanciando CustomerPlan, el modelo intermedio que requiere plan_id y customer_id [3:30].
  • Sin el session.refresh, la respuesta aparece vacía porque los datos no se actualizan en memoria [4:10].

¿Cómo listar las suscripciones de un customer?

Para consultar todos los planes a los que un customer está suscrito, se define un endpoint GET en /customers/{customer_id}/plans [4:28].

python @router.get("/customers/{customer_id}/plans") async def list_customer_plans(customer_id: int, session: Session): customer_db = session.get(Customer, customer_id) if not customer_db: raise HTTPException(status_code=404, detail="Customer not found") return customer_db.plans

  • Se obtiene el customer por ID.
  • Si no existe, se retorna un error 404.
  • Si existe, se retornan directamente los planes gracias a la relación definida en el modelo [4:50].

¿Qué reto queda pendiente para practicar?

Con la relación muchos a muchos completamente funcional, un excelente ejercicio es agregar un campo de estado dentro del modelo CustomerPlan y luego modificar el endpoint de listado para filtrar únicamente los planes que estén activos [5:15]. ¿Ya lo intentaste? Comparte tu solución y cuéntanos cómo resolviste el filtrado.