Si has trabajado con FastAPI probablemente has ejecutado alguna vez algo parecido a esto:
uvicorn main:app
El comando parece sencillo, pero detrás hay una pieza importante de la arquitectura web moderna de Python.
Uvicorn no “es” FastAPI. FastAPI tampoco “es” el servidor. Entre ambos existe un contrato llamado ASGI.
ASGI significa Asynchronous Server Gateway Interface. Es una especificación que define cómo un servidor capaz de recibir conexiones de red se comunica con una aplicación Python.
La idea se puede visualizar así:
cliente
↓ HTTP / WebSocket
servidor ASGI
↓ ASGI
framework / aplicación Python
↓
tu código
Por ejemplo:
navegador
↓
Uvicorn
↓ ASGI
FastAPI
↓
endpoint Python
Ese pequeño bloque explica una distinción que suele confundirse cuando uno empieza con FastAPI: ASGI no es un framework y tampoco es un servidor. Es la interfaz que permite que ambos se entiendan.
El problema que ASGI intenta resolver
Antes de ASGI, el estándar dominante para aplicaciones web Python era —y sigue siendo muy importante— WSGI, Web Server Gateway Interface.
WSGI fue extraordinariamente útil porque desacopló los servidores de los frameworks. Un servidor compatible con WSGI podía ejecutar una aplicación compatible con WSGI sin que ambos tuvieran que diseñarse específicamente uno para el otro.
El modelo encajaba muy bien con la web clásica:
request
↓
procesar
↓
response
Pero internet dejó de ser solamente una secuencia de peticiones cortas con una respuesta final.
Aparecieron casos como:
- WebSockets;
- conexiones que permanecen abiertas;
- streaming;
- eventos enviados progresivamente;
- muchas operaciones de I/O concurrentes;
- aplicaciones que necesitan recibir y enviar eventos durante la vida de una conexión.
La propia especificación de ASGI explica que WSGI está ligado al ciclo HTTP tradicional request/response, mientras que ASGI fue diseñado para representar protocolos y conexiones con múltiples eventos a lo largo del tiempo.
Ahí está la diferencia conceptual más importante.
ASGI convierte una conexión en eventos
Una aplicación ASGI moderna se puede reducir conceptualmente a una función asíncrona con esta forma:
async def application(scope, receive, send):
...
Los tres parámetros son la esencia del protocolo.
scope
Describe la conexión.
Es un diccionario con información como el tipo de protocolo, la ruta y otros metadatos asociados a esa conexión.
Por ejemplo:
scope["type"]
puede ser:
http
o:
websocket
receive
Es una función awaitable que permite a la aplicación recibir eventos.
Por ejemplo, el cuerpo de una petición HTTP llega mediante eventos como:
http.request
En un WebSocket pueden aparecer eventos como:
websocket.connect
websocket.receive
websocket.disconnect
send
Permite a la aplicación enviar eventos al servidor.
Para una respuesta HTTP, una aplicación puede enviar primero:
http.response.start
y después:
http.response.body
Para un WebSocket podría enviar:
websocket.send
Por eso ASGI encaja mejor con una conexión bidireccional y de larga duración que el modelo request/response puramente síncrono.
Una aplicación ASGI mínima
No es normal escribir aplicaciones ASGI directamente, pero hacerlo una vez ayuda a entender la arquitectura:
async def app(scope, receive, send):
assert scope["type"] == "http"
await send({
"type": "http.response.start",
"status": 200,
"headers": [(b"content-type", b"text/plain")],
})
await send({
"type": "http.response.body",
"body": b"Hola desde ASGI",
})
Aquí no aparece FastAPI.
No aparece Django.
No aparece siquiera una abstracción de Request o Response.
Sólo existe el contrato ASGI.
En una aplicación real, el framework se encarga de traducir esos eventos de bajo nivel a una API mucho más cómoda.
FastAPI es una aplicación ASGI
Con FastAPI normalmente escribimos algo como:
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def home():
return {"message": "Hola"}
Y luego:
uvicorn main:app
Ese comando significa aproximadamente:
uvicorn
importa main.py
encuentra el objeto app
comprueba que puede tratarlo como aplicación ASGI
abre sockets
convierte tráfico de red en eventos ASGI
entrega esos eventos a FastAPI
FastAPI procesa la ruta, ejecuta nuestro código y genera la respuesta; Uvicorn se ocupa de hablar con la red.
ASGI es la frontera común entre ambos.
La documentación de FastAPI lo resume de forma directa: FastAPI es un framework web ASGI y para servirlo necesitamos un programa servidor ASGI, como Uvicorn o alternativas como Hypercorn.
Entonces, ¿qué es Uvicorn?
Uvicorn es un servidor ASGI.
Su trabajo está más cerca de esta capa:
socket / HTTP
↓
Uvicorn
↓
ASGI
Mientras que FastAPI vive en esta otra:
ASGI
↓
FastAPI
↓
lógica de aplicación
La separación es valiosa porque permite cambiar componentes.
Conceptualmente podrías ejecutar una aplicación ASGI con otro servidor compatible sin reescribir tu aplicación alrededor de ese servidor concreto.
Django también puede hablar ASGI
ASGI no es exclusivo de FastAPI.
Django soporta tanto WSGI como ASGI. Un proyecto Django moderno incluye un objeto application en su configuración ASGI que puede ser servido por servidores compatibles como Uvicorn, Daphne, Hypercorn o Granian.
Esto permite que Django participe en arquitecturas asíncronas, aunque existe una advertencia importante: estar detrás de ASGI no convierte automáticamente todo el código en no bloqueante.
Si dentro de un handler asíncrono llamas una librería síncrona que bloquea el thread, el event loop no puede hacer magia.
async no significa “más rápido” en todo
Éste es uno de los errores más comunes.
ASGI resulta especialmente poderoso cuando tenemos mucho trabajo de I/O:
esperar una API
esperar una base de datos
esperar Redis
esperar un archivo remoto
esperar mensajes de un socket
Mientras una coroutine espera, el event loop puede avanzar otras tareas.
Imagina 1.000 conexiones que pasan gran parte de su tiempo esperando datos externos. Un modelo asíncrono puede aprovechar muy bien esos huecos.
Pero si la operación es:
calcular vídeo
comprimir grandes archivos
hacer inferencia pesada en CPU
procesar millones de números
el problema es diferente.
El trabajo CPU-bound sigue consumiendo CPU. En esos casos podemos necesitar procesos separados, workers, colas de tareas u otras estrategias de paralelismo.
ASGI mejora el modelo de concurrencia para ciertas cargas; no elimina las leyes de la computación.
WSGI vs ASGI
Una comparación simplificada:
| Característica | WSGI | ASGI |
|---|---|---|
| HTTP tradicional | Sí | Sí |
| Modelo síncrono | Nativo | Compatible |
async/await | No como modelo nativo | Sí |
| WebSockets | No como parte del estándar | Sí |
| Conexiones largas | Poco natural | Natural |
| Eventos múltiples por conexión | No es el modelo central | Sí |
| Frameworks típicos | Flask clásico, Django WSGI | FastAPI, Starlette, Django ASGI |
Eso no significa que WSGI esté “muerto”.
Para muchas aplicaciones CRUD tradicionales, el modelo síncrono sigue siendo perfectamente razonable. Además, ASGI fue diseñado teniendo en cuenta interoperabilidad con aplicaciones WSGI existentes.
La elección depende de la carga y de la arquitectura, no de que una sigla sea más nueva.
Por qué WebSockets hacen tan visible la diferencia
Un endpoint HTTP clásico suele tener una vida breve:
cliente → request → response → fin
Un WebSocket se parece más a esto:
cliente conecta
↓
servidor acepta
↓
cliente envía mensaje
↓
servidor responde
↓
cliente envía otro mensaje
↓
servidor puede enviar eventos
↓
...
↓
conexión termina
La aplicación necesita reaccionar a múltiples eventos durante la misma conexión.
El modelo scope + receive + send de ASGI fue diseñado precisamente para representar este tipo de interacción.
Una forma útil de recordarlo
Si sólo recuerdas una cosa, que sea ésta:
ASGI = contrato
Uvicorn = servidor
FastAPI / Starlette / Django = framework o aplicación
async/await = modelo de ejecución que ASGI puede aprovechar
O, de forma visual:
Internet
↓
Uvicorn / Hypercorn / Daphne
↓
========== ASGI ==========
↓
FastAPI / Starlette / Django
↓
Tu lógica de negocio
ASGI no es la aplicación que ve el usuario.
No es el servidor que abre el puerto.
No es el framework donde defines @app.get().
Es el lenguaje común entre esas capas.
Y una vez que se entiende esa frontera, buena parte del ecosistema web asíncrono de Python deja de parecer una colección de nombres desconectados y empieza a verse como una arquitectura coherente.