Module 1: Setup and First API

uvicorn y Servidor de Desarrollo

Descripción de la cápsula

FastAPI no puede recibir requests HTTP por sí solo. Necesita un servidor que escuche en un puerto, reciba las peticiones y las pase al framework. Ese servidor es uvicorn — el servidor ASGI estándar para FastAPI.

En esta cápsula profundizas en uvicorn: qué es un servidor ASGI, cómo ejecutarlo con --reload, cómo cambiar puerto y host, cómo interpretar los logs, y cómo detener el servidor correctamente. Dominar estas opciones te permitirá iterar rápido durante el desarrollo y diagnosticar problemas cuando algo falle.


¿Qué es uvicorn?

uvicorn es un servidor ASGI (Asynchronous Server Gateway Interface) de alto rendimiento para aplicaciones Python. Es el equivalente moderno de Gunicorn (que sirve aplicaciones WSGI como Flask y Django clásico).

ASGI vs WSGI

AspectoWSGI (Flask, Django)ASGI (FastAPI)
ProtocoloSíncronoAsíncrono
ConcurrenciaUn request por workerMúltiples requests simultáneos
WebSocketsNo nativoSoportado
Servidor típicoGunicornuvicorn

FastAPI está construido sobre ASGI. Por eso usas uvicorn, no Gunicorn.

Flujo request → response

Cliente (navegador, curl, Postman)
    ↓ HTTP request
uvicorn (escucha en puerto 8000)
    ↓ pasa el request a la aplicación
FastAPI (tu app)
    ↓ ejecuta la función del endpoint
Tu código (root(), health_check(), etc.)
    ↓ retorna un dict
FastAPI (serializa a JSON)
    ↓ pasa la response a uvicorn
uvicorn → HTTP response al cliente

Ejecutar uvicorn

Comando básico

uvicorn app.main:app --reload

Desglose del comando

ParteSignificado
uvicornEl ejecutable del servidor
app.mainMódulo Python (app/main.py)
appVariable que contiene la instancia FastAPI
--reloadReinicia al detectar cambios en el código (solo desarrollo)

Output esperado

INFO:     Will watch for changes in these directories: ['/ruta/al/proyecto']
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     Started reloader process [12345] using StatReload
INFO:     Started server process [12346]
INFO:     Waiting for application startup.
INFO:     Application startup complete.

Hot reload: Iterar sin reiniciar

El flag --reload hace que uvicorn monitoree tus archivos Python. Cuando guardas un cambio, el servidor se reinicia automáticamente.

Cómo funciona

  1. Editas app/main.py
  2. Guardas el archivo
  3. uvicorn detecta el cambio
  4. Reinicia el proceso
  5. Tu cambio está activo — no necesitas presionar Ctrl+C ni volver a ejecutar

Output al detectar cambios

WARNING:  StatReload detected changes in 'app/main.py'. Reloading...
INFO:     Started server process [12347]
INFO:     Waiting for application startup.
INFO:     Application startup complete.

Cuándo NO usar --reload

  • Producción: En producción usas workers y configuración distinta
  • Si el reload falla: A veces un error de sintaxis impide la recarga; reinicia manualmente

Puerto y host

Puerto por defecto: 8000

# Equivalente explícito
uvicorn app.main:app --reload --port 8000

Cambiar de puerto

# Usar puerto 3000 (común en desarrollo frontend)
uvicorn app.main:app --reload --port 3000

# Usar puerto 8080
uvicorn app.main:app --reload --port 8080

Host: localhost vs todas las interfaces

HostComportamiento
127.0.0.1 (por defecto)Solo accesible desde tu máquina
0.0.0.0Accesible desde cualquier IP (red local, Docker)
# Accesible desde otros dispositivos en tu red (ej: probar desde el móvil)
uvicorn app.main:app --reload --host 0.0.0.0

# Combinado con puerto custom
uvicorn app.main:app --reload --port 3000 --host 0.0.0.0

Logs: Interpretar la salida

Logs normales

INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     Started reloader process [12345] using StatReload
INFO:     Started server process [12346]
INFO:     Waiting for application startup.
INFO:     Application startup complete.

Log de cada request

Cuando haces un request (desde navegador o curl):

INFO:     127.0.0.1:54321 - "GET / HTTP/1.1" 200 OK
ParteSignificado
127.0.0.1:54321IP y puerto del cliente
GET /Método y ruta
HTTP/1.1Versión de HTTP
200 OKStatus code de la respuesta

Logs de error

ERROR:    Exception in ASGI application
Traceback (most recent call last):
  ...

Si ves un traceback, hay un error en tu código. Lee el mensaje y la línea indicada para corregirlo.


Detener el servidor

Forma correcta

Presiona Ctrl+C en la terminal donde está corriendo uvicorn.

^CINFO:     Shutting down
INFO:     Finished server process [12346]

Si no responde

  1. Intenta Ctrl+C varias veces
  2. Cierra la terminal
  3. Si el puerto queda ocupado:
    # Mac/Linux: encontrar proceso en puerto 8000
    lsof -i :8000
    kill -9 <PID>

Ejecutar desde Python

Puedes lanzar uvicorn desde un script:

# run.py en la raíz del proyecto
import uvicorn

if __name__ == "__main__":
    uvicorn.run(
        "app.main:app",  # módulo:variable como string
        host="127.0.0.1",
        port=8000,
        reload=True,
    )
python run.py

Útil para configuraciones más complejas o scripts de arranque personalizados.


Workers y producción

En desarrollo usas un solo worker con --reload. En producción la configuración cambia:

  • Workers: Múltiples procesos para manejar más carga
  • Sin reload: El código no cambia en producción
  • Gunicorn + uvicorn: Gunicorn puede usar uvicorn como worker para producción

Para esta guía solo necesitas el modo desarrollo. El deployment se cubre en guías posteriores.


Resumen de opciones CLI

OpciónDescripciónEjemplo
--hostInterfaz de escucha--host 0.0.0.0
--portPuerto--port 3000
--reloadHot reload (solo dev)--reload
--workersNúmero de workers (prod)--workers 4
--log-levelNivel de log--log-level debug

Resumen de comandos útiles

# Desarrollo estándar
uvicorn app.main:app --reload

# Puerto y host custom
uvicorn app.main:app --reload --port 3000 --host 0.0.0.0

# Desde run.py
python run.py

# Ver ayuda
uvicorn --help

Guarda estos comandos como referencia. Los usarás constantemente durante el desarrollo.


Troubleshooting

Problema 1: Hot reload no detecta cambios

Causa: Editaste un archivo fuera del directorio monitoreado, o hay un error de sintaxis que impide la recarga.

Solución:

# Reiniciar manualmente
# Ctrl+C para detener
uvicorn app.main:app --reload

Verifica que no hay errores en la terminal. Un SyntaxError puede bloquear el reload.

Problema 2: Puerto ya en uso

Causa: Otro proceso (otra instancia de uvicorn, otro servidor) usa el puerto 8000.

Solución:

# Opción 1: Usar otro puerto
uvicorn app.main:app --reload --port 8001

# Opción 2: Matar el proceso (Mac/Linux)
lsof -i :8000
kill -9 <PID>

Problema 3: No puedo acceder desde otro dispositivo

Causa: Estás usando el host por defecto 127.0.0.1, que solo acepta conexiones locales.

Solución:

uvicorn app.main:app --reload --host 0.0.0.0

Asegúrate de que el firewall permita conexiones entrantes en el puerto.

Problema 4: uvicorn muy lento al iniciar

Causa: En proyectos grandes, el reload puede tardar. O [standard] no está instalado.

Solución:

pip install "uvicorn[standard]"

La variante [standard] incluye uvloop y httptools para mejor rendimiento.

Problema 5: "Address already in use" aunque maté el proceso

Causa: El sistema operativo puede tardar unos segundos en liberar el puerto.

Solución: Espera 5-10 segundos y vuelve a intentar. O usa otro puerto temporalmente.


Variables de entorno (opcional)

Puedes usar variables de entorno para configuración:

export UVICORN_HOST=0.0.0.0
export UVICORN_PORT=3000
uvicorn app.main:app --reload --host $UVICORN_HOST --port $UVICORN_PORT

O en un archivo .env con python-dotenv (se cubre en guías posteriores). Para ahora, los flags de CLI son suficientes.


Monitoreo de archivos con --reload

Por defecto uvicorn monitorea el directorio desde donde lo ejecutas. Si tu estructura es:

proyecto/
├── app/
│   └── main.py
└── tests/
    └── test_main.py

Cambios en app/main.py disparan reload. Cambios en tests/ también, porque están en el mismo árbol. Si tuvieras código en otro directorio fuera del proyecto, podrías usar --reload-dir para limitar el monitoreo (menos común).


Conexión con el ciclo de desarrollo

Tu flujo típico será:

  1. Editar app/main.py (o otros archivos)
  2. Guardar
  3. uvicorn detecta el cambio (si usas --reload)
  4. Reinicio automático
  5. Probar en navegador o /docs
  6. Repetir

El tiempo entre "guardar" y "ver resultado" es de segundos. Eso acelera la iteración y hace que el desarrollo sea más fluido.


Recursos de debug

Si algo falla al arrancar uvicorn:

  • Ver versión: uvicorn --version
  • Modo verbose: uvicorn app.main:app --reload --log-level debug
  • Probar import manual: Desde la raíz del proyecto, python -c "from app.main import app; print(app)" debe imprimir la instancia FastAPI sin errores

Si el import falla, el problema está en tu código, no en uvicorn. Revisa el traceback completo.

Checklist rápido antes de pedir ayuda

  1. ¿El venv está activo? (debe verse (venv) en el prompt)
  2. ¿Estás en la raíz del proyecto? (ls debe mostrar la carpeta app/)
  3. ¿El archivo existe? (ls app/main.py)
  4. ¿La variable se llama app? (grep "app = FastAPI" app/main.py)
  5. ¿El comando es correcto? (uvicorn app.main:app con dos puntos)

Si las cinco respuestas son sí y sigue fallando, el error suele estar en el contenido de main.py (sintaxis, import faltante, etc.).

Atajos de teclado útiles

En la terminal donde corre uvicorn:

  • Ctrl+C — Detener el servidor
  • Ctrl+Z (evitar) — Suspendería el proceso; usa Ctrl+C en su lugar

Si accidentalmente suspendes con Ctrl+Z, escribe fg para traer el proceso al frente, luego Ctrl+C para detenerlo correctamente.

Resumen de la cápsula

En esta cápsula cubriste: qué es uvicorn y ASGI, cómo ejecutar con --reload, cambio de puerto y host, interpretación de logs, detención del servidor, y troubleshooting común. En la siguiente crearás tus primeros endpoints GET y explorarás la documentación automática en /docs.


Ejercicios

Ejercicio 1: Cambiar puerto y host (Fácil)

Ejecuta uvicorn en el puerto 3000, accesible desde cualquier IP. Luego verifica que puedes acceder desde http://localhost:3000 y desde la IP de tu máquina en la red local.

Ver solución
uvicorn app.main:app --reload --port 3000 --host 0.0.0.0

Para obtener tu IP local (Mac/Linux):

ip addr show | grep "inet "  # Linux
ifconfig | grep "inet "      # Mac

Luego prueba desde otro dispositivo: http://<tu-ip>:3000

Explicación: --host 0.0.0.0 escucha en todas las interfaces. --port 3000 usa ese puerto.

Ejercicio 2: Interpretar logs (Fácil)

Arranca uvicorn y haz 3 requests: uno a /, uno a /health (si existe), y uno a una ruta inexistente. Anota qué aparece en los logs para cada uno.

Ver solución
GET /         → "GET / HTTP/1.1" 200 OK
GET /health   → "GET /health HTTP/1.1" 200 OK
GET /ruta-xyz → "GET /ruta-xyz HTTP/1.1" 404 Not Found

Explicación: Los logs muestran método, ruta y status code. Un 404 indica que la ruta no existe.

Ejercicio 3: run.py con parámetros (Medio)

Crea un archivo run.py que ejecute uvicorn con reload=True, puerto 8080 y host 0.0.0.0. Lanza la app con python run.py y verifica que funciona.

Ver solución
# run.py
import uvicorn

if __name__ == "__main__":
    uvicorn.run(
        "app.main:app",
        host="0.0.0.0",
        port=8080,
        reload=True,
    )
python run.py
# Acceder en http://localhost:8080

Explicación: uvicorn.run() acepta el módulo como string. El reload=True equivale a --reload en CLI.

Ejercicio 4: Diagnosticar problema de puerto (Medio)

Tienes el error ERROR: [Errno 48] Address already in use. Escribe los pasos que seguirías para identificar qué proceso usa el puerto 8000 y liberarlo (Mac/Linux).

Ver solución
# 1. Identificar proceso
lsof -i :8000

# Output ejemplo:
# COMMAND   PID   USER   FD   TYPE  DEVICE  SIZE/OFF  NODE  NAME
# Python  12345  mike    3u  IPv4  ...      0t0      TCP  *:8000 (LISTEN)

# 2. Matar el proceso
kill -9 12345  # Usar el PID de la salida anterior

# 3. Verificar que el puerto está libre
lsof -i :8000
# No output = puerto libre

# 4. Reiniciar uvicorn
uvicorn app.main:app --reload

Explicación: lsof -i :8000 lista procesos que usan el puerto. kill -9 fuerza la terminación.

Ejercicio 5: Hot reload con error (Medio)

Edita app/main.py e introduce un error de sintaxis (por ejemplo, borra los dos puntos de def root()). Guarda. ¿Qué pasa en la terminal de uvicorn? Corrige el error y guarda de nuevo. ¿Qué ocurre?

Ver solución

Con error de sintaxis:

  • uvicorn intenta recargar
  • Falla al importar el módulo
  • Muestra un traceback con SyntaxError
  • El servidor puede quedar en estado inconsistente

Tras corregir:

  • uvicorn detecta el cambio
  • Recarga correctamente
  • Application startup complete aparece de nuevo

Explicación: El hot reload depende de que Python pueda importar el módulo. Un SyntaxError impide la importación, así que el reload falla.

Ejercicio 6: Comparar con y sin --reload (Fácil)

Ejecuta uvicorn sin --reload. Edita app/main.py, guarda y refresca el navegador. ¿Ves el cambio? Reinicia uvicorn manualmente (Ctrl+C y volver a ejecutar). ¿Ahora sí? Explica la diferencia.

Ver solución

Sin --reload: El cambio NO se refleja hasta que reinicias uvicorn manualmente. El servidor carga el código una vez al iniciar y no lo vuelve a cargar.

Con --reload: El cambio se refleja automáticamente tras guardar. uvicorn monitorea archivos y reinicia el proceso cuando detecta cambios.

Explicación: En desarrollo siempre usa --reload para iterar rápido. En producción no lo usarías; ahí se usa configuración con workers.


Diferencias entre desarrollo y producción

AspectoDesarrolloProducción
Comandouvicorn app.main:app --reloaduvicorn app.main:app --workers 4
--reloadSí (detecta cambios)No (código no cambia)
Workers1Múltiples según carga
Host127.0.0.10.0.0.0 o según deployment
Detrás deNada (acceso directo)Nginx, load balancer

En esta guía solo trabajas en modo desarrollo. El deployment se cubre en guías específicas.

Por qué --reload es solo para desarrollo

El hot reload usa un proceso que monitorea el sistema de archivos. Eso consume recursos y añade complejidad. En producción el código no cambia (se despliega una nueva versión), así que no necesitas monitoreo. Además, con múltiples workers, el reload podría causar condiciones de carrera. Por eso --reload está pensado únicamente para desarrollo local.


Resumen

  • uvicorn es el servidor ASGI que ejecuta tu aplicación FastAPI
  • uvicorn app.main:app --reload inicia el servidor con hot reload
  • --port y --host controlan puerto e interfaces de escucha
  • --host 0.0.0.0 permite acceso desde otros dispositivos en la red
  • ✅ Los logs muestran cada request con método, ruta y status code
  • Ctrl+C detiene el servidor correctamente
  • ✅ Hot reload detecta cambios y reinicia; errores de sintaxis pueden bloquearlo

Próxima cápsula: Primer Endpoint, JSON y Docs — crearás endpoints GET, retornarás JSON y explorarás la documentación automática.


Recursos Adicionales

  1. Uvicorn Documentation - Documentación oficial
  2. Uvicorn Settings - Todas las opciones de configuración
  3. ASGI Specification - Protocolo que implementa uvicorn
  4. FastAPI - Run a Server - Cómo ejecutar FastAPI
  5. Gunicorn + Uvicorn - Deployment en producción
  6. HTTP Status Codes - Referencia de códigos

Módulo 1, Cápsula 04 — FastAPI Fundamentals Guide