Una alternativa a agregar los tags a cada endpoint, es agregar lo siguiente al router para aplicarlo a todos por defecto:
router = APIRouter(tags = ['customers'])
Cuando tu aplicación crece, mantener todos los endpoints en un solo archivo se vuelve un dolor de cabeza. Aquí aprenderás a estructurar tu proyecto FastAPI con APIRouter, separar responsabilidades por recursos y agrupar rutas con tags para que tu documentación se mantenga clara y tu código sea fácil de mantener.
Esta guía es útil si ya construiste tus primeros endpoints y quieres llevar tu API a un nivel profesional, listo para producción y para trabajar en equipo.
¿Por qué dividir tu aplicación FastAPI en módulos?
Un archivo único con cientos de líneas hace que cualquier cambio sea engorroso. Separar el proyecto en módulos te permite tocar solo lo necesario, hacer pull requests limpios y escalar sin perder el control.
La idea central es simple: cada recurso (clientes, transacciones, facturas) vive en su propio archivo dentro de una carpeta dedicada. Y aquí entra la pieza clave, el APIRouter, que funciona como una miniaplicación de FastAPI capaz de agrupar endpoints relacionados.
¿Qué es APIRouter en FastAPI? Es una clase que actúa como una miniaplicación dentro de tu app principal. Te deja agrupar endpoints por recurso y aplicarles configuraciones comunes sin tocar uno por uno [02:15].
¿Cómo se organiza la estructura de carpetas recomendada?
La documentación oficial sugiere una estructura clara que separa la aplicación, los routers y la configuración. Esta es la base que vas a replicar.
Dentro de tu proyecto necesitas estos elementos [01:30]:
app que agrupa los archivos de la aplicación.__init__.py dentro de app para convertirla en módulo y permitir imports.main.py con la instancia principal de FastAPI.dependencies.py para inyectar dependencias compartidas.routers con su propio __init__.py y un archivo por recurso (customer.py, transactions.py, invoices.py).db.py fuera de app con la configuración de base de datos.models.py para modelos pequeños, o una carpeta models/ cuando son muchos.requirements.txt para reproducir el entorno en otro servidor.Un detalle importante: el __init__.py solo va dentro de app y routers, nunca en la raíz del proyecto, porque convertirías el root en un módulo y romperías los imports.
¿Cuándo conviene separar los modelos en una carpeta?
Si tienes uno, dos o tres modelos, mantenlos en un solo archivo models.py. Es más simple y evitas imports innecesarios. Cuando la cantidad crece, conviene crear una carpeta models/ con su __init__.py y un archivo por modelo.
¿Cómo crear un router para customer paso a paso?
El flujo es directo: mover los endpoints del recurso a su propio archivo y reemplazar la instancia app por una instancia de APIRouter.
Dentro de routers/customer.py haces los imports relativos hacia atrás con dos puntos para alcanzar models y db desde la carpeta superior [04:20]:
python from ..models import Customer, CustomerCreate, CustomerUpdate from ..db import SessionDB from fastapi import APIRouter, status, HTTPException from sqlmodel import select
router = APIRouter()
Luego reemplazas todos los decoradores @app.get, @app.post, etc., por @router.get, @router.post. Los endpoints siguen funcionando igual, solo cambia quién los registra.
¿Qué hace el archivo
__init__.py? Convierte una carpeta en un módulo de Python para que puedas importar sus archivos desde otras partes del proyecto. Sin él, los imports fallan [01:55].
¿Cómo registrar el router en la aplicación principal?
En main.py eliminas los imports que ya no usas (porque los endpoints se movieron) e incluyes el router con include_router:
python from fastapi import FastAPI from .routers import customer
app = FastAPI() app.include_router(customer.router)
Fíjate en el punto antes de routers: indica un import relativo dentro del paquete app. Si lo olvidas, verás un error de módulo no encontrado.
¿Cómo agrupar endpoints en la documentación con tags?
Por defecto, los endpoints aparecen bajo el grupo default en la documentación de Swagger. Para agruparlos por recurso, agregas el parámetro tags al crear el router [07:40]:
python router = APIRouter(tags=["customers"])
Al recargar la documentación, todos los endpoints del archivo aparecen agrupados bajo customers, plegables con un clic. Esto mejora la lectura para cualquier persona que consuma tu API.
¿Cómo ejecutar la aplicación con la nueva estructura?
Antes ejecutabas fastapi apuntando a un archivo en la raíz. Ahora debes indicar la ruta completa al main.py dentro de app [06:10]:
bash fastapi dev app/main.py
Si ves un error que menciona models, revisa dos cosas: que no exista un __init__.py en la raíz del proyecto y que los imports relativos en tus routers usen la cantidad correcta de puntos.
Los errores de imports en Python son comunes cuando reorganizas archivos. Tómalos como parte natural del proceso y verifica siempre la jerarquía de carpetas.
¿Qué ganas al estructurar tu API de esta forma?
Al separar cada recurso en su propio router obtienes ventajas concretas para el día a día del desarrollo:
APIRouter.Como reto, replica el proceso para los módulos de transactions e invoices. Crea sus archivos en routers/, mueve los endpoints correspondientes, registra cada router en main.py con include_router y no olvides agregar su tags para que queden agrupados en la documentación.
¿En qué parte de la reorganización te trabaste? Cuéntame en los comentarios cómo resolviste los imports relativos.
Cuando tu aplicación crece, mantener todos los endpoints en un solo archivo se vuelve un dolor de cabeza. Aquí aprenderás a estructurar tu proyecto FastAPI con APIRouter, separar responsabilidades por recursos y agrupar rutas con tags para que tu documentación se mantenga clara y tu código sea fácil de mantener.
Esta guía es útil si ya construiste tus primeros endpoints y quieres llevar tu API a un nivel profesional, listo para producción y para trabajar en equipo.
Un archivo único con cientos de líneas hace que cualquier cambio sea engorroso. Separar el proyecto en módulos te permite tocar solo lo necesario, hacer pull requests limpios y escalar sin perder el control.
La idea central es simple: cada recurso (clientes, transacciones, facturas) vive en su propio archivo dentro de una carpeta dedicada. Y aquí entra la pieza clave, el APIRouter, que funciona como una miniaplicación de FastAPI capaz de agrupar endpoints relacionados.
¿Qué es APIRouter en FastAPI? Es una clase que actúa como una miniaplicación dentro de tu app principal. Te deja agrupar endpoints por recurso y aplicarles configuraciones comunes sin tocar uno por uno [02:15].
La documentación oficial sugiere una estructura clara que separa la aplicación, los routers y la configuración. Esta es la base que vas a replicar.
Dentro de tu proyecto necesitas estos elementos [01:30]:
app que agrupa los archivos de la aplicación.__init__.py dentro de app para convertirla en módulo y permitir imports.main.py con la instancia principal de FastAPI.dependencies.py para inyectar dependencias compartidas.routers con su propio __init__.py y un archivo por recurso (customer.py, transactions.py, invoices.py).db.py fuera de app con la configuración de base de datos.models.py para modelos pequeños, o una carpeta models/ cuando son muchos.requirements.txt para reproducir el entorno en otro servidor.Un detalle importante: el __init__.py solo va dentro de app y routers, nunca en la raíz del proyecto, porque convertirías el root en un módulo y romperías los imports.
Si tienes uno, dos o tres modelos, mantenlos en un solo archivo models.py. Es más simple y evitas imports innecesarios. Cuando la cantidad crece, conviene crear una carpeta models/ con su __init__.py y un archivo por modelo.
El flujo es directo: mover los endpoints del recurso a su propio archivo y reemplazar la instancia app por una instancia de APIRouter.
Dentro de routers/customer.py haces los imports relativos hacia atrás con dos puntos para alcanzar models y db desde la carpeta superior [04:20]:
python from ..models import Customer, CustomerCreate, CustomerUpdate from ..db import SessionDB from fastapi import APIRouter, status, HTTPException from sqlmodel import select
router = APIRouter()
Luego reemplazas todos los decoradores @app.get, @app.post, etc., por @router.get, @router.post. Los endpoints siguen funcionando igual, solo cambia quién los registra.
¿Qué hace el archivo
__init__.py? Convierte una carpeta en un módulo de Python para que puedas importar sus archivos desde otras partes del proyecto. Sin él, los imports fallan [01:55].
En main.py eliminas los imports que ya no usas (porque los endpoints se movieron) e incluyes el router con include_router:
python from fastapi import FastAPI from .routers import customer
app = FastAPI() app.include_router(customer.router)
Fíjate en el punto antes de routers: indica un import relativo dentro del paquete app. Si lo olvidas, verás un error de módulo no encontrado.
Por defecto, los endpoints aparecen bajo el grupo default en la documentación de Swagger. Para agruparlos por recurso, agregas el parámetro tags al crear el router [07:40]:
python router = APIRouter(tags=["customers"])
Al recargar la documentación, todos los endpoints del archivo aparecen agrupados bajo customers, plegables con un clic. Esto mejora la lectura para cualquier persona que consuma tu API.
Antes ejecutabas fastapi apuntando a un archivo en la raíz. Ahora debes indicar la ruta completa al main.py dentro de app [06:10]:
bash fastapi dev app/main.py
Si ves un error que menciona models, revisa dos cosas: que no exista un __init__.py en la raíz del proyecto y que los imports relativos en tus routers usen la cantidad correcta de puntos.
Los errores de imports en Python son comunes cuando reorganizas archivos. Tómalos como parte natural del proceso y verifica siempre la jerarquía de carpetas.
Al separar cada recurso en su propio router obtienes ventajas concretas para el día a día del desarrollo:
APIRouter.Como reto, replica el proceso para los módulos de transactions e invoices. Crea sus archivos en routers/, mueve los endpoints correspondientes, registra cada router en main.py con include_router y no olvides agregar su tags para que queden agrupados en la documentación.
¿En qué parte de la reorganización te trabaste? Cuéntame en los comentarios cómo resolviste los imports relativos.
Una alternativa a agregar los tags a cada endpoint, es agregar lo siguiente al router para aplicarlo a todos por defecto:
router = APIRouter(tags = ['customers'])
Por si no se ve el comando es: fastapi dev app/main.py
Aunque puede ser un poco complicada de entender, esta clase es muy potente y puede ser utilizada para resolver problemas complejos y específicos.
Arquitectura de APIs escalables en FastAPI implica diseñar y estructurar tu aplicación para manejar un crecimiento en la cantidad de usuarios, datos y peticiones. Aquí tienes una guía práctica para lograrlo:
Organiza tu código en módulos o capas para que sea mantenible y escalable:
users.py, products.py, etc.) y agrégalas al proyecto principal.Ejemplo de estructura:
app/ ├── main.py ├── routers/ │ ├── users.py │ ├── products.py ├── models/ │ ├── user.py │ ├── product.py ├── services/ │ ├── user_service.py │ ├── product_service.py ├── db/ │ ├── database.py │ ├── migrations/
Alembic para gestionar cambios en los esquemas de la base de datos.asyncpg o conexiones síncronas bien gestionadas.Depends para manejar configuraciones como bases de datos, autenticación o validación de roles.Ejemplo:
from fastapi import APIRouter, Depends
router = APIRouter(prefix="/users", tags=["users"])
@router.get("/") async def list_users(): return {"message": "List of users"}
Implementa mecanismos para soportar múltiples instancias de tu API:
Uvicorn Workers: Ejecuta varios trabajadores con uvicorn o gunicorn.uvicorn app.main:app --host 0.0.0.0 --port 8000 --workers 4
Balanceadores de carga: Usa Nginx o servicios como AWS Elastic Load Balancer.
Integra un sistema de cache como Redis para reducir la carga en la base de datos:
Ejemplo con aioredis:
import aioredis
redis = aioredis.from_url("redis://localhost")
Ejemplo:
from fastapi.middleware.cors import CORSMiddleware
app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], )
Escribe pruebas unitarias y de integración para garantizar la calidad:
Loguru o servicios como Datadog.from fastapi import FastAPI from app.routers import users, products from app.db.database import create_db_and_tables
app = FastAPI()
@app.on_event("startup") def on_startup(): create_db_and_tables()
app.include_router(users.router) app.include_router(products.router)
Con esta arquitectura, tu API en FastAPI estará lista para manejar tanto un desarrollo inicial como un crecimiento significativo.
Pienso que para evitar que el archivo models.py se vuelva infinitamente largo se puede crear una carpeta models y poner ahí distintos archivos con los modelos necesarios.
Aquí mi solución al reto:from app.routers.customers import router as router_customersfrom app.routers.transactions import router as router_transactionsfrom app.routers.invoices import router as router_invoicesfrom db import SessionDep, create_all_tables routers = [router_customers, router_transactions, router_invoices] app = FastAPI(lifespan = create_all_tables)for router in routers: app.include_router(router)
from app.routers.customers import router as router_customers
from app.routers.transactions import router as router_transactions
from app.routers.invoices import router as router_invoices
from db import SessionDep, create_all_tables
routers = [router_customers, router_transactions, router_invoices]
app = FastAPI(lifespan = create_all_tables)
for router in routers:
app.include_router(router)
Otra opción para agregar los tags a los endpoints, es desde el main.py agregar esto al registrar el router:
** app.include_router(company_router, prefix="/companies", tags=["Companies"])
El ejemplo es de un proyecto que estoy desarrollando aparte.
Si han venido usando UV en lugar de pip el nuevo directorio es app.main en lugar de app
así: uv run uvicorn app.main:app --reload
Recomiendo que estudien (comprender mejor la organización de una API o App). Sobre: Microservicios, Arquitectura, Patrones de Arquitectura de Software y de Diseño. Refactorizar. Todos estos términos y conceptos (Te va a ayudar a en un futuro poder organizar todo). Pero, lo mejor es que, ayudará a resolver tu necesidad (necesitas agregar y usar para tu proyecto).
Agregar el tag "customers" a cada endpoint en customers.py permite agrupar esos endpoints en la documentación generada por FastAPI. Esto mejora la organización y facilita la navegación para los desarrolladores, ya que pueden encontrar rápidamente todos los endpoints relacionados con el recurso "customers". Además, simplifica la gestión de cambios, ya que al modificar o revisar endpoints específicos, puedes enfocarte únicamente en el archivo correspondiente, mejorando la claridad y el mantenimiento del código.