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
| Aspecto | WSGI (Flask, Django) | ASGI (FastAPI) |
|---|---|---|
| Protocolo | Síncrono | Asíncrono |
| Concurrencia | Un request por worker | Múltiples requests simultáneos |
| WebSockets | No nativo | Soportado |
| Servidor típico | Gunicorn | uvicorn |
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
| Parte | Significado |
|---|---|
uvicorn | El ejecutable del servidor |
app.main | Módulo Python (app/main.py) |
app | Variable que contiene la instancia FastAPI |
--reload | Reinicia 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
- Editas
app/main.py - Guardas el archivo
- uvicorn detecta el cambio
- Reinicia el proceso
- 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
| Host | Comportamiento |
|---|---|
127.0.0.1 (por defecto) | Solo accesible desde tu máquina |
0.0.0.0 | Accesible 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
| Parte | Significado |
|---|---|
127.0.0.1:54321 | IP y puerto del cliente |
GET / | Método y ruta |
HTTP/1.1 | Versión de HTTP |
200 OK | Status 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
- Intenta
Ctrl+Cvarias veces - Cierra la terminal
- 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ón | Descripción | Ejemplo |
|---|---|---|
--host | Interfaz de escucha | --host 0.0.0.0 |
--port | Puerto | --port 3000 |
--reload | Hot reload (solo dev) | --reload |
--workers | Número de workers (prod) | --workers 4 |
--log-level | Nivel 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á:
- Editar
app/main.py(o otros archivos) - Guardar
- uvicorn detecta el cambio (si usas
--reload) - Reinicio automático
- Probar en navegador o
/docs - 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
- ¿El venv está activo? (debe verse
(venv)en el prompt) - ¿Estás en la raíz del proyecto? (
lsdebe mostrar la carpetaapp/) - ¿El archivo existe? (
ls app/main.py) - ¿La variable se llama
app? (grep "app = FastAPI" app/main.py) - ¿El comando es correcto? (
uvicorn app.main:appcon 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 completeaparece 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
| Aspecto | Desarrollo | Producción |
|---|---|---|
| Comando | uvicorn app.main:app --reload | uvicorn app.main:app --workers 4 |
| --reload | Sí (detecta cambios) | No (código no cambia) |
| Workers | 1 | Múltiples según carga |
| Host | 127.0.0.1 | 0.0.0.0 o según deployment |
| Detrás de | Nada (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 --reloadinicia el servidor con hot reload - ✅
--porty--hostcontrolan puerto e interfaces de escucha - ✅
--host 0.0.0.0permite acceso desde otros dispositivos en la red - ✅ Los logs muestran cada request con método, ruta y status code
- ✅
Ctrl+Cdetiene 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
- Uvicorn Documentation - Documentación oficial
- Uvicorn Settings - Todas las opciones de configuración
- ASGI Specification - Protocolo que implementa uvicorn
- FastAPI - Run a Server - Cómo ejecutar FastAPI
- Gunicorn + Uvicorn - Deployment en producción
- HTTP Status Codes - Referencia de códigos
Módulo 1, Cápsula 04 — FastAPI Fundamentals Guide