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ísticaWSGIASGI
HTTP tradicionalSíSí
Modelo síncronoNativoCompatible
async/awaitNo como modelo nativoSí
WebSocketsNo como parte del estándarSí
Conexiones largasPoco naturalNatural
Eventos múltiples por conexiónNo es el modelo centralSí
Frameworks típicosFlask clásico, Django WSGIFastAPI, 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.

Fuentes