El Modelo del Ciclo de Vida de la Solicitud de FastAPI
A menudo se describe FastAPI característica por característica: soporte async, documentación automática, inyección de dependencias, validación Pydantic.
Esas características son reales, pero no son complementos separados añadidos a un framework web genérico.
Son un ciclo de vida: una solicitud entra como un evento ASGI, se empareja con una operación de ruta cuyo grafo de dependencias ya se resolvió al inicio, sus entradas se validan antes de que se ejecute el cuerpo de tu función, y sus salidas se revalidan y filtran antes de que salgan.
Entender bien FastAPI significa entender ese ciclo de vida como un único pipeline, no como una lista de verificación de capacidades independientes.
Esta página construye ese modelo mental; Conceptos Básicos de FastAPI y Inyección de Dependencias cubren la sintaxis práctica que este modelo explica desde abajo.
Resumen
- Una solicitud de FastAPI atraviesa un único ciclo de vida: despacho ASGI, resolución de dependencias, validación Pydantic, ejecución del manejador, serialización de la respuesta, y el comportamiento de cada etapa solo tiene sentido a la luz de las otras.
- Por Qué Importa: El comportamiento más confuso de FastAPI (por qué una función síncrona no bloqueó, por qué los errores de validación nunca llegan a tu código, por qué una dependencia se ejecutó dos veces) se remonta a una etapa de este ciclo de vida mal entendida, no a un error.
- Conceptos Clave: ASGI, el grafo de dependencias, la validación de Pydantic, la división síncrona/asíncrona en pool de hilos, el filtrado de response_model.
- Cuándo Usar Este Modelo: Para razonar sobre dónde ocurre la validación, decidir si un manejador debe ser
async def, depurar por qué el código de limpieza de una dependencia se ejecutó en un momento inesperado, o explicar por qué FastAPI necesita Starlette y Pydantic debajo de él. - Limitaciones / Compensaciones: La flexibilidad del ciclo de vida proviene de la introspección en tiempo de ejecución y la resolución de dependencias por solicitud, ambas añaden un costo medible en comparación con un framework sin capa de validación o DI.
- Temas Relacionados: Enrutamiento y middleware de Starlette, el modelo de solicitud síncrona de WSGI, el motor de validación de Pydantic, Uvicorn y servidores ASGI en general.
Fundamentos
FastAPI no es un servidor, y ni siquiera es realmente un framework completo en el sentido en que lo es Django.
Es una capa tipada de solicitud/respuesta construida sobre Starlette, un toolkit ASGI que ya proporciona enrutamiento, middleware y el cliente de prueba, además de Pydantic, que proporciona el motor de validación y serialización de datos.
ASGI (Asynchronous Server Gateway Interface) es la pieza que hace esto posible: a diferencia del contrato síncrono de una solicitud por llamada de WSGI, una aplicación ASGI es una única llamada asíncrona que recibe scope, un awaitable receive y un awaitable send, y puede mantener una conexión abierta, esperar E/S sin bloquear otras solicitudes, y manejar WebSockets usando la misma interfaz.
Una forma útil de visualizar la relación: Starlette es el motor que ejecuta el protocolo ASGI y encuentra la función correcta para llamar; FastAPI es lo que sucede cuando además te aseguras de que las entradas y salidas de la función estén tipadas y validadas.
Ese encuadre importa porque una gran parte de lo que la gente llama "características de FastAPI" —tipado de parámetros de ruta/consulta, cuerpos de solicitud, filtrado de respuestas— son en realidad características de Pydantic que FastAPI conecta en Starlette en los puntos correctos del ciclo de vida.
Mecánicas e Interacciones
El ciclo de vida tiene en realidad dos fases: una que se ejecuta una vez al inicio, y otra que se ejecuta en cada solicitud.
Al inicio, FastAPI inspecciona la firma de cada función de operación de ruta —sus parámetros, sus anotaciones de tipo y cualquier valor predeterminado de Depends(...)— y construye un grafo de dependencias para esa ruta, incluyendo las subdependencias de las dependencias, todo resuelto de antemano para que el trabajo por solicitud sea solo recorrer un árbol conocido.
Solicitud entrante
-> Servidor ASGI (Uvicorn) pasa el scope a la app
-> El router de Starlette empareja ruta + método
-> FastAPI recorre el grafo de dependencias preconstruido (de arriba abajo, subdependencias primero)
-> Pydantic valida los parámetros de ruta/consulta/cuerpo contra los modelos de la ruta
-> Se ejecuta la función de operación de ruta (async en el loop, sync en un pool de hilos)
-> El valor de retorno se valida/filtra contra response_model
-> Se envía la respuesta; las dependencias de tipo yield ejecutan su limpieza despuésCada solicitud recorre entonces ese grafo: las dependencias se resuelven de arriba abajo, una determinada función de dependencia solo se invoca una vez por solicitud incluso si otras dependencias dependen de ella, y cualquier dependencia definida con yield tiene su código posterior a yield diferido hasta después de que se haya generado la respuesta.
La división síncrona/asíncrona es una mecánica central, no una elección de estilo: una operación de ruta o dependencia async def se ejecuta directamente en el bucle de eventos, mientras que una def normal se despacha automáticamente a un pool de hilos externo para que no pueda bloquear otras solicitudes concurrentes —por eso "simplemente no uses async" no hace que un endpoint escale peor por sí solo, aunque sí limita la concurrencia al tamaño del pool de hilos.
La validación ocurre antes de que se ejecute el cuerpo de tu función, no dentro de ella: FastAPI analiza el cuerpo ASGI crudo, lo empareja con el modelo Pydantic o el tipo escalar del parámetro, y lanza automáticamente un 422 con errores a nivel de campo si falla, por lo que un manejador solo ve datos ya válidos y ya tipados.
from fastapi import Depends, FastAPI
app = FastAPI()
def get_settings():
return {"env": "prod"}
def get_client(settings: dict = Depends(get_settings)):
return {"base_url": settings["env"]}
@app.get("/status")
def status(client: dict = Depends(get_client)):
return client # get_settings y get_client se ejecutaron una vez cada uno, no dos vecesConsideraciones y Aplicaciones Avanzadas
Dado que el grafo de dependencias y los modelos Pydantic se resuelven a través de la maquinaria de introspección de Python, FastAPI incurre en un costo real por solicitud que un framework sin capa de validación no tiene: esta es la compensación por obtener esquemas OpenAPI automáticos, autocompletado en el editor y seguridad en los límites de forma gratuita.
El pool de hilos que soporta las operaciones de ruta síncronas tiene un tamaño finito (Starlette lo establece por defecto en un pool de trabajadores limitado), por lo que una aplicación que consiste principalmente en funciones síncronas que realizan E/S bloqueante eventualmente se pondrá en cola detrás de ese pool bajo carga, lo que es un techo de escalabilidad que es fácil de pasar por alto hasta que el tráfico aumenta; consulta Rutas Async y Bases de Datos para ver la alternativa de drivers asíncronos.
response_model no es solo metadato para la documentación: FastAPI realmente revalida y filtra el objeto que tu función devuelve contra él, razón por la cual devolver una instancia de ORM directamente es seguro desde una perspectiva de fuga de datos siempre que el modelo de respuesta excluya campos sensibles, pero también significa que un valor de retorno incorrecto falla en la etapa de respuesta, no en la etapa de solicitud.
Las tareas en segundo plano (BackgroundTasks) se ejecutan después de que la respuesta se ha enviado al cliente pero aún dentro del mismo ciclo de vida del worker/solicitud, lo que las hace adecuadas para registrar o notificaciones de "disparar y olvidar", pero no para nada que el cliente necesite saber que tuvo éxito; consulta Tareas y Workers en Segundo Plano para ver dónde se encuentra ese límite.
| Enfoque | Fortaleza | Debilidad | Mejor Ajuste |
|---|---|---|---|
| Ciclo de vida ASGI + DI + Pydantic de FastAPI | Validación automática, documentación e inyección de dependencias tipada con async nativo | Sobrecarga de introspección y validación por solicitud; dependencias síncronas limitadas por el tamaño del pool de hilos | APIs donde la seguridad de entrada, la generación de esquemas y la E/S asíncrona son importantes |
| Starlette puro (sin capa FastAPI) | Mínima sobrecarga, control ASGI completo | Sin validación automática, DI u OpenAPI; todo hecho a mano | Servicios críticos de latencia que no necesitan contratos de solicitud tipados |
| Framework WSGI (ej. Flask) | Modelo mental más simple, ecosistema síncrono maduro | Sin concurrencia async nativa; la E/S bloqueante ocupa un worker | Aplicaciones principalmente síncronas sin altas demandas de E/S concurrente |
Conceptos Erróneos Comunes
- "Marcar una ruta como
async defla hace automáticamente más rápida." Solo ayuda cuando el manejador realmente está esperando E/S; una operaciónasync defintensiva en CPU sigue bloqueando el bucle de eventos completo durante la duración de ese trabajo, lo cual unadefsíncrona ejecutándose en el pool de hilos no haría. - "Depends es solo una forma de llamar a una función auxiliar." Una dependencia se resuelve una vez por solicitud, se almacena en caché para esa solicitud si se reutiliza en otro lugar del mismo grafo, y puede ser anulada por completo en pruebas a través de
app.dependency_overrides—nada de esto lo obtienes con una simple llamada a función. - "La validación ocurre dentro de mi función de endpoint." Ocurre antes de que tu función sea invocada; cuando tu código se ejecuta, los datos ya han pasado las verificaciones de Pydantic, razón por la cual rara vez es necesario lanzar tu propio 422 manualmente.
- "response_model es solo para la documentación OpenAPI." Valida y filtra activamente el valor que tu función devuelve contra ese modelo, que es el mecanismo que evita que un campo como una contraseña cifrada se filtre en una respuesta JSON, incluso si el objeto devuelto todavía tiene ese atributo.
- "FastAPI es un servidor web desde cero." No tiene servidor propio; Uvicorn (u otro servidor ASGI) es lo que realmente acepta conexiones, y FastAPI es la aplicación tipada a la que llama ese servidor.
Preguntas Frecuentes
¿Qué significa realmente "ASGI" para cómo FastAPI maneja una solicitud?
Significa que la aplicación es una única llamada asíncrona que recibe scope, receive y send, lo que permite a FastAPI mantener una conexión abierta y esperar E/S (llamadas a bases de datos, llamadas HTTP, mensajes WebSocket) sin bloquear otras solicitudes concurrentes en el mismo bucle de eventos.
¿Es FastAPI su propio servidor web?
No. Uvicorn u otro servidor ASGI acepta las conexiones TCP reales y llama al objeto de aplicación de FastAPI; el trabajo de FastAPI comienza una vez que una solicitud ya ha llegado a él como un evento ASGI.
¿Cuándo se construye el grafo de dependencias de una ruta: por solicitud o una sola vez?
Una vez, al inicio, cuando FastAPI inspecciona la firma de cada operación de ruta y sus valores predeterminados de Depends(...). Por solicitud, solo recorre ese grafo ya conocido en lugar de redescubrirlo.
¿Una dependencia utilizada por otras dos dependencias se ejecuta dos veces en una solicitud?
No. FastAPI resuelve y almacena en caché cada función de dependencia una vez por solicitud por defecto, por lo que las subdependencias compartidas (como una sesión de base de datos) se calculan una sola vez, incluso si varias otras dependencias las necesitan.
¿Debería cada operación de ruta ser `async def`?
Solo si la función realmente espera E/S. Una operación async def intensiva en CPU bloquea todo el bucle de eventos durante la duración de ese trabajo; una def síncrona que realiza el mismo trabajo de CPU se ejecuta en un pool de hilos en su lugar, lo que no bloquea el trabajo asíncrono de otras solicitudes.
¿Qué sucede si los datos de la solicitud fallan la validación de Pydantic?
FastAPI devuelve automáticamente una respuesta 422 con detalles de error a nivel de campo, antes de que el cuerpo de tu función de operación de ruta se ejecute; tu código nunca ve una entrada inválida.
¿Qué hace realmente `response_model` en tiempo de ejecución?
Valida y filtra el valor que tu función devuelve contra ese modelo, eliminando cualquier campo que no esté declarado en él, razón por la cual se utiliza para evitar que campos internos se filtren en una respuesta JSON.
¿Cuándo se ejecutan realmente los bloques de limpieza de dependencias basados en `yield`?
Después de que la respuesta ya ha sido generada (y, dependiendo de la versión y configuración, potencialmente después de haber sido enviada), lo que los hace adecuados para cerrar una sesión o conexión de base de datos, pero inadecuados para cualquier cosa que deba afectar al cuerpo de la respuesta en sí.
¿Por qué una operación de ruta síncrona podría ser un riesgo de escalabilidad?
Porque se ejecuta en un pool de hilos limitado; una vez que las solicitudes síncronas concurrentes exceden el tamaño del pool, las adicionales se ponen en cola detrás de él, creando latencia que el código limitado por E/S asíncrona que comparte el bucle de eventos no incurriría.
¿Puedo anular una dependencia para pruebas?
Sí: app.dependency_overrides[some_dependency] = fake_dependency la reemplaza para toda la aplicación o sesión de prueba sin tocar el código de la ruta, lo cual solo funciona porque las dependencias se resuelven a través de este grafo en lugar de ser llamadas directamente.
¿Las tareas en segundo plano retrasan la respuesta al cliente?
No, se ejecutan después de que la respuesta ha sido enviada, razón exacta por la cual son apropiadas para registrar o notificaciones, pero no para nada que el llamador necesite confirmar antes de que la solicitud se complete.
¿Por qué FastAPI necesita tanto Starlette como Pydantic?
Starlette proporciona el enrutamiento ASGI, el middleware y las mecánicas de despacho; Pydantic proporciona el motor de validación y serialización de datos. La contribución de FastAPI es conectar modelos de solicitud/respuesta tipados en los puntos de despacho de Starlette y generar OpenAPI a partir de ellos.
Relacionados
- Conceptos Básicos de FastAPI - rutas prácticas, parámetros y documentación automática
- Inyección de Dependencias -
Depends, subdependencias y anulaciones de pruebas en la práctica - Modelos de Solicitud y Respuesta - modelos Pydantic en el límite de solicitud/respuesta
- Rutas Async y Bases de Datos - el lado de E/S asíncrona de la división síncrona/asíncrona
- Middleware y Manejo de Errores - dónde se sitúa el middleware en relación con este ciclo de vida
- Tareas y Workers en Segundo Plano - qué se ejecuta después de que se envía la respuesta
Versiones de Stack: Esta página fue escrita para FastAPI 0.115+ en Python 3.14 (mantenimiento: 3.13), usando Pydantic 2 para la validación.