Module 1: Setup and First API
Proyecto: Hello World API
Descripción del proyecto
En este proyecto integras todo lo que aprendiste en el Módulo 1: crearás una API completa con estructura profesional, múltiples endpoints organizados por categorías, documentación automática personalizada, y respuestas JSON consistentes.
No es un "hola mundo" trivial. Es un API con identidad propia, estructura escalable, y documentación que podrías mostrar a otro desarrollador. Es el esqueleto real sobre el que construirás los módulos 2-6 de esta guía. Cada módulo posterior agregará una capa: CRUD (Módulo 2), parámetros avanzados (Módulo 3), validación Pydantic (Módulo 4), error handling y CORS (Módulo 5), hasta llegar al proyecto final To-Do List API (Módulo 6).
El objetivo es que al terminar, tengas un proyecto en tu máquina que funciona, tiene buena estructura, y sirve como base real — no como ejemplo descartable.
Objetivo del proyecto
Construir una Hello World API profesional que demuestre dominio de setup, endpoints GET, path parameters, y documentación automática en FastAPI.
Al completar este proyecto:
- ✅ Tienes un proyecto FastAPI con estructura de carpetas profesional
- ✅ Tu API tiene al menos 6 endpoints GET organizados con tags
- ✅ La documentación en
/docstiene título, descripción y versión personalizados - ✅ Path parameters funcionan con validación de tipos automática
- ✅ Respuestas JSON siguen un formato consistente
- ✅ El servidor corre con hot reload y puedes iterar rápido
¿Por qué este proyecto?
Un Hello World API podría ser un solo endpoint. Pero este proyecto tiene 6 endpoints intencionalmente:
- Endpoints informativos (
/,/health,/info) — practican rutas estáticas y respuestas fijas - Endpoints dinámicos (
/greet/{name},/repeat/{message}/{times}) — practican path parameters con diferentes tipos - Endpoint con lógica (
/age/{years}) — practica condicionales dentro de un endpoint
Esta variedad asegura que dominas los patrones básicos, no solo el caso trivial.
Además, este proyecto te obliga a pensar en organización desde el inicio — tags, documentación, formato de respuestas consistente.
Estos hábitos en el Módulo 6 harán la diferencia entre un proyecto amateur y uno profesional.
Especificaciones técnicas
Stack
- Lenguaje: Python 3.9+
- Framework: FastAPI
- Servidor: uvicorn con hot reload
- Dependencias:
fastapi,uvicorn[standard]
Estructura del proyecto
fastapi-fundamentals/
├── venv/
├── app/
│ ├── __init__.py
│ └── main.py
├── requirements.txt
└── .gitignore
Esta estructura es idéntica a la que configuraste en la Cápsula 02. No necesitas crear archivos adicionales — todo el código va en app/main.py.
En módulos posteriores esta estructura crecerá con archivos como models.py y carpetas como routers/, pero por ahora un solo archivo es suficiente para mantener el foco en los conceptos fundamentales.
Setup (si empiezas desde cero)
mkdir fastapi-fundamentals
cd fastapi-fundamentals
python -m venv venv
source venv/bin/activate # Mac/Linux
pip install fastapi "uvicorn[standard]"
pip freeze > requirements.txt
mkdir -p app
touch app/__init__.py app/main.py
Funcionalidades obligatorias
Tu Hello World API debe tener estos endpoints:
1. Root — Información del servicio
GET /
Response:
{
"service": "Hello World API",
"version": "1.0.0",
"status": "running",
"documentation": "/docs"
}
2. Health Check
GET /health
Response:
{
"status": "healthy"
}
3. API Info — Metadatos completos
GET /info
Response:
{
"name": "Hello World API",
"description": "Mi primera API profesional con FastAPI",
"version": "1.0.0",
"author": "Tu Nombre",
"python_framework": "FastAPI",
"documentation_urls": {
"swagger": "/docs",
"redoc": "/redoc",
"openapi": "/openapi.json"
}
}
4. Greet — Saludo personalizado
GET /greet/{name}
Response:
{
"message": "Hello, Maria!",
"name": "Maria"
}
5. Repeat — Repetir un mensaje N veces
GET /repeat/{message}/{times}
Response:
{
"original": "hola",
"times": 3,
"result": "hola hola hola"
}
6. Age Category — Clasificar por edad
GET /age/{years}
Response:
{
"age": 25,
"category": "adult",
"can_vote": true,
"can_drive": true
}
Formato de respuesta consistente
Todas las respuestas deben seguir estas convenciones:
- Siempre retornar diccionarios (JSON objects), no strings ni listas sueltas
- Usar snake_case para las keys (
can_vote, nocanVote) - Incluir el input del usuario en la respuesta cuando sea relevante (facilita debugging)
- Los endpoints de error deben incluir una key
"error"con un mensaje descriptivo
# ✅ Buena respuesta — consistente, informativa
{
"age": 25,
"category": "adult",
"can_vote": true
}
# ❌ Mala respuesta — solo el resultado sin contexto
"adult"
Documentación personalizada
Tu aplicación FastAPI debe incluir:
- Título: "Hello World API"
- Descripción: Un párrafo describiendo la API
- Versión: "1.0.0"
- Tags: Al menos 3 tags para organizar endpoints (ej: "General", "System", "Features")
- Cada endpoint debe tener
summaryo docstring descriptivo
Código completo comentado
app/main.py
from fastapi import FastAPI
app = FastAPI(
title="Hello World API",
description="Mi primera API profesional con FastAPI. Incluye endpoints de información, saludo personalizado y clasificación por edad.",
version="1.0.0",
)
# --- Endpoints Generales ---
@app.get("/", tags=["General"], summary="Service Info")
def root():
"""Punto de entrada principal. Retorna información básica del servicio."""
return {
"service": "Hello World API",
"version": "1.0.0",
"status": "running",
"documentation": "/docs"
}
@app.get("/health", tags=["System"], summary="Health Check")
def health_check():
"""Verifica que el servicio está activo y respondiendo correctamente."""
return {"status": "healthy"}
@app.get("/info", tags=["System"], summary="API Metadata")
def api_info():
"""
Retorna metadatos completos de la API.
Incluye nombre, versión, autor y URLs de documentación.
"""
return {
"name": "Hello World API",
"description": "Mi primera API profesional con FastAPI",
"version": "1.0.0",
"author": "Tu Nombre",
"python_framework": "FastAPI",
"documentation_urls": {
"swagger": "/docs",
"redoc": "/redoc",
"openapi": "/openapi.json"
}
}
# --- Endpoints de Features ---
@app.get("/greet/{name}", tags=["Features"], summary="Greet User")
def greet(name: str):
"""
Saluda al usuario por su nombre.
- **name**: Nombre de la persona (string)
"""
return {
"message": f"Hello, {name}!",
"name": name
}
@app.get("/repeat/{message}/{times}", tags=["Features"], summary="Repeat Message")
def repeat_message(message: str, times: int):
"""
Repite un mensaje N veces.
- **message**: Texto a repetir
- **times**: Cantidad de repeticiones (entero positivo)
"""
repeated = " ".join([message] * times)
return {
"original": message,
"times": times,
"result": repeated
}
@app.get("/age/{years}", tags=["Features"], summary="Age Category")
def age_category(years: int):
"""
Clasifica una edad en categoría y determina permisos básicos.
**Categorías:**
- **child**: 0-12 años
- **teenager**: 13-17 años
- **adult**: 18-64 años
- **senior**: 65+ años
"""
if years < 0:
return {
"error": "Age cannot be negative",
"input": years
}
if years <= 12:
category = "child"
elif years <= 17:
category = "teenager"
elif years <= 64:
category = "adult"
else:
category = "senior"
return {
"age": years,
"category": category,
"can_vote": years >= 18,
"can_drive": years >= 16
}
Ejecutar
uvicorn app.main:app --reload
Probar todos los endpoints
# General
curl -s http://127.0.0.1:8000/ | python -m json.tool
curl -s http://127.0.0.1:8000/health | python -m json.tool
curl -s http://127.0.0.1:8000/info | python -m json.tool
# Features
curl -s http://127.0.0.1:8000/greet/FastAPI | python -m json.tool
curl -s http://127.0.0.1:8000/repeat/hola/3 | python -m json.tool
curl -s http://127.0.0.1:8000/age/25 | python -m json.tool
curl -s http://127.0.0.1:8000/age/10 | python -m json.tool
curl -s http://127.0.0.1:8000/age/70 | python -m json.tool
# Documentación
# Abre en navegador: http://127.0.0.1:8000/docs
# Abre en navegador: http://127.0.0.1:8000/redoc
Outputs esperados:
# GET /
{
"service": "Hello World API",
"version": "1.0.0",
"status": "running",
"documentation": "/docs"
}
# GET /health
{
"status": "healthy"
}
# GET /greet/FastAPI
{
"message": "Hello, FastAPI!",
"name": "FastAPI"
}
# GET /repeat/hola/3
{
"original": "hola",
"times": 3,
"result": "hola hola hola"
}
# GET /age/25
{
"age": 25,
"category": "adult",
"can_vote": true,
"can_drive": true
}
# GET /age/10
{
"age": 10,
"category": "child",
"can_vote": false,
"can_drive": false
}
Criterios de éxito
Tu proyecto está completo cuando:
- ✅ El servidor inicia sin errores con
uvicorn app.main:app --reload - ✅ Todos los 6 endpoints retornan respuestas JSON correctas
- ✅
/docsmuestra la documentación con título "Hello World API" - ✅ Los endpoints están organizados en al menos 3 tags
- ✅ Path parameters funcionan (
/greet/nombre,/age/25) - ✅ Validación de tipos funciona (
/age/abcretorna error 422) - ✅ Hot reload funciona (editas código, guardas, y el cambio se refleja)
- ✅ La estructura del proyecto usa
app/main.py(nomain.pyen raíz)
Checklist de completitud
Estructura:
- [ ] Carpeta app/ con __init__.py y main.py
- [ ] requirements.txt generado
- [ ] .gitignore configurado
- [ ] Virtual environment funcional
Endpoints (6):
- [ ] GET / — Info del servicio
- [ ] GET /health — Health check
- [ ] GET /info — Metadatos completos
- [ ] GET /greet/{name} — Saludo personalizado
- [ ] GET /repeat/{message}/{times} — Repetir mensaje
- [ ] GET /age/{years} — Categoría por edad
Documentación:
- [ ] Título personalizado en /docs
- [ ] Descripción de la API
- [ ] Versión configurada
- [ ] Tags organizando endpoints
- [ ] Summary o docstring en cada endpoint
Funcionamiento:
- [ ] Servidor inicia sin errores
- [ ] Hot reload funciona
- [ ] Validación de tipos funciona (int en path params)
- [ ] Respuestas JSON consistentes
Errores comunes
Error 1: "detail": "Not Found" en un endpoint
Causa: La ruta en el navegador/curl no coincide exactamente con la del decorador.
Solución:
# Si definiste:
@app.get("/greet/{name}")
# Accede a:
# ✅ /greet/Maria
# ❌ /Greet/Maria (case sensitive)
# ❌ /greet/ (falta el parámetro)
# ❌ /greet (falta / y parámetro)
Error 2: times se interpreta como string
Causa: Olvidaste el type hint int en el parámetro.
Solución:
# ❌ Sin type hint — times es string
@app.get("/repeat/{message}/{times}")
def repeat_message(message: str, times): # times será str
repeated = " ".join([message] * times) # Error: can't multiply by str
# ✅ Con type hint — times es int
@app.get("/repeat/{message}/{times}")
def repeat_message(message: str, times: int): # times será int
repeated = " ".join([message] * times) # Funciona
Error 3: El diccionario JSON retorna en una sola línea ilegible
Causa: Esto es normal. JSON por defecto es compacto. Para formato bonito:
Solución:
# Desde terminal, usa python para formatear:
curl -s http://127.0.0.1:8000/info | python -m json.tool
# O instala jq (herramienta de línea de comandos para JSON):
curl -s http://127.0.0.1:8000/info | jq
Error 4: Los tags no aparecen en /docs
Causa: Olvidaste el parámetro tags en el decorador.
Solución:
# ❌ Sin tags
@app.get("/health")
def health_check():
return {"status": "healthy"}
# ✅ Con tags
@app.get("/health", tags=["System"])
def health_check():
return {"status": "healthy"}
Error 5: Hot reload no detecta cambios
Causa: Editaste un archivo fuera de la carpeta que uvicorn monitorea, o hay un error de sintaxis que impide la recarga.
Solución:
# Verificar que no hay errores de sintaxis en la terminal de uvicorn
# Si ves un traceback, corrígelo primero
# Si no detecta cambios, reinicia manualmente:
# Ctrl+C para detener
uvicorn app.main:app --reload
Verificación paso a paso
Usa esta guía para verificar que tu proyecto funciona correctamente:
Paso 1: Verificar estructura
# Desde la raíz del proyecto
ls -la app/
# Debe mostrar:
# __init__.py
# main.py
ls requirements.txt
# Debe existir
ls .gitignore
# Debe existir
Paso 2: Verificar servidor
# Iniciar servidor
uvicorn app.main:app --reload
# En otra terminal, probar root:
curl -s http://127.0.0.1:8000/ | python -m json.tool
# Debe retornar JSON con "service", "version", "status", "documentation"
Paso 3: Verificar documentación
Abre http://127.0.0.1:8000/docs en tu navegador:
- ¿El título dice "Hello World API"? ✅
- ¿Ves la descripción personalizada? ✅
- ¿Los endpoints están agrupados en tags? ✅
- ¿Puedes hacer "Try it out" en cualquier endpoint? ✅
Paso 4: Verificar path parameters
# String parameter
curl -s http://127.0.0.1:8000/greet/TestUser | python -m json.tool
# Debe incluir "TestUser" en la respuesta
# Int parameter
curl -s http://127.0.0.1:8000/age/25 | python -m json.tool
# Debe retornar category "adult"
# Validación de tipos
curl -s http://127.0.0.1:8000/age/abc | python -m json.tool
# Debe retornar error 422
Paso 5: Verificar hot reload
- Con el servidor corriendo, edita cualquier respuesta en
app/main.py - Guarda el archivo
- Verifica que la terminal de uvicorn muestra "Reloading..."
- Refresca el navegador — el cambio debe reflejarse
Ideas para extender (opcional)
Si terminas rápido y quieres practicar más, agrega estos endpoints. No son obligatorios pero refuerzan lo aprendido:
@app.get("/reverse/{text}", tags=["Features"], summary="Reverse Text")
def reverse_text(text: str):
"""Invierte un string."""
return {
"original": text,
"reversed": text[::-1]
}
@app.get("/count/{text}", tags=["Features"], summary="Count Characters")
def count_chars(text: str):
"""Cuenta caracteres, palabras y vocales en un texto."""
vowels = sum(1 for c in text.lower() if c in "aeiou")
return {
"text": text,
"characters": len(text),
"words": len(text.split("-")),
"vowels": vowels
}
@app.get("/fibonacci/{n}", tags=["Features"], summary="Fibonacci Number")
def fibonacci(n: int):
"""Calcula el n-ésimo número de Fibonacci."""
if n < 0:
return {"error": "n must be non-negative"}
a, b = 0, 1
for _ in range(n):
a, b = b, a + b
return {
"n": n,
"fibonacci": a
}
Troubleshooting del proyecto
Si algo no funciona, sigue este diagnóstico en orden:
1. ¿El venv está activo?
→ ¿Ves (venv) en el prompt?
→ source venv/bin/activate
2. ¿FastAPI está instalado?
→ pip show fastapi
→ Si no, pip install fastapi "uvicorn[standard]"
3. ¿El servidor inicia?
→ uvicorn app.main:app --reload
→ Si hay error, lee el traceback completo
4. ¿El endpoint existe?
→ Abre /docs y verifica que la ruta está listada
→ Si no aparece, revisa el decorador
5. ¿La respuesta es correcta?
→ Usa "Try it out" en /docs para probar
→ Compara la respuesta con la especificación
Problemas frecuentes y soluciones rápidas
| Síntoma | Causa probable | Solución |
|---|---|---|
ModuleNotFoundError: No module named 'fastapi' | venv no activo | source venv/bin/activate |
ModuleNotFoundError: No module named 'app' | Directorio incorrecto | cd a la raíz del proyecto |
ERROR: Address already in use | Puerto 8000 ocupado | --port 8001 o matar proceso |
404 Not Found en un endpoint | Ruta mal escrita | Comparar ruta con decorador |
422 Unprocessable Entity | Tipo de parámetro incorrecto | Verificar type hints |
| Cambios no se reflejan | Hot reload no detectó | Ctrl+C y reiniciar uvicorn |
/docs vacío | Error de sintaxis en código | Revisar terminal de uvicorn |
SyntaxError al iniciar | Error en main.py | Revisar traceback completo |
Rúbrica de evaluación (100 puntos)
Estructura y setup (20 puntos)
- (5 pts) Virtual environment creado y funcional
- (5 pts) Estructura
app/con__init__.pyymain.py - (5 pts)
requirements.txtgenerado con dependencias - (5 pts)
.gitignoreconfigurado correctamente
Endpoints (40 puntos)
- (8 pts)
GET /retorna información del servicio - (5 pts)
GET /healthretorna status healthy - (7 pts)
GET /inforetorna metadatos completos - (7 pts)
GET /greet/{name}funciona con path parameter string - (7 pts)
GET /repeat/{message}/{times}funciona con path parameter int - (6 pts)
GET /age/{years}retorna categoría correcta
Documentación (20 puntos)
- (5 pts) Título personalizado visible en
/docs - (5 pts) Descripción de la API configurada
- (5 pts) Endpoints organizados con tags (mínimo 3)
- (5 pts) Summary o docstring en cada endpoint
Calidad de código (20 puntos)
- (5 pts) Código limpio y legible
- (5 pts) Type hints en todos los path parameters
- (5 pts) Respuestas JSON consistentes (diccionarios)
- (5 pts) Hot reload funcionando correctamente
Extra credit (hasta +10 puntos)
- (+5 pts) Endpoint adicional creativo con lógica interesante
- (+3 pts) Docstrings con formato Markdown renderizado en
/docs - (+2 pts) Verificación de edge cases (ej: edad negativa)
Conexión con el siguiente módulo
Tu Hello World API es el punto de partida del Módulo 2 (Path Operations). En el siguiente módulo:
- Agregarás POST, PUT, PATCH y DELETE — hasta ahora solo tienes GET
- Implementarás datos en memoria — una lista de Python como mock database
- Harás CRUD completo — crear, leer, actualizar y eliminar recursos
El código de app/main.py crecerá. La estructura app/ se mantendrá igual — la base que construiste aquí es duradera.
Lo que ya tienes funcionando:
- Setup con venv + uvicorn + hot reload → lo conservas
- Estructura
app/main.py→ la amplías - Documentación automática → se actualiza sola al agregar endpoints
- Path parameters → los seguirás usando
Lo que agregarás en Módulo 2:
- Operaciones POST, PUT, PATCH, DELETE
- Lista en memoria como almacenamiento temporal
- Endpoints que modifican estado (no solo lectura)
- Response status codes apropiados (201 Created, 204 No Content)
Reflexión: Lo que ya dominas
Detente un momento y nota lo que ya sabes hacer después de este módulo:
- Crear un proyecto Python profesional con aislamiento de dependencias
- Definir endpoints HTTP que manejan requests y retornan JSON
- Usar path parameters con validación automática de tipos
- Generar documentación interactiva sin esfuerzo adicional
- Iterar rápido con hot reload — tu ciclo de feedback es de segundos
Estos 5 skills son la base de todo lo que viene. El Módulo 2 agrega verbos HTTP (POST, PUT, DELETE). El Módulo 3 agrega query parameters y request body. El Módulo 4 agrega validación con Pydantic. Cada módulo es una capa nueva sobre esta base sólida.
No subestimes lo que ya construiste. Un servidor con documentación automática, validación de tipos y hot reload es más de lo que muchos tutoriales cubren en varias horas.
Resumen
En este proyecto integraste los conceptos fundamentales del Módulo 1:
- Setup profesional: Virtual environment, estructura
app/, requirements.txt - Endpoints GET: 6 endpoints con rutas estáticas y dinámicas (path parameters)
- Path parameters con tipos: Validación automática de
intystr - Documentación personalizada: Título, descripción, versión, tags y docstrings
- Hot reload: Flujo de desarrollo ágil con uvicorn
--reload - Respuestas consistentes: Diccionarios JSON con formato predecible
Tu Hello World API no es un ejercicio descartable — es el esqueleto real sobre el que construirás el resto de la guía. Guarda este proyecto: lo abrirás al inicio del Módulo 2 y seguirás construyendo sobre él.
Módulo 1 completado. Siguiente parada: Path Operations — donde tu API aprende a crear, actualizar y eliminar recursos.
Lo que llevas al Módulo 2
Antes de avanzar, asegúrate de tener claro esto — es lo que asumirás como conocido a partir de ahora:
| Concepto | Nivel esperado |
|---|---|
| Virtual environment | Sabes crear, activar y desactivar |
| pip install | Sabes instalar paquetes y generar requirements.txt |
Estructura app/ | Entiendes por qué usas un paquete Python |
@app.get("/ruta") | Sabes que conecta ruta + verbo + función |
| Path parameters | Sabes usar {param} en rutas con type hints |
| uvicorn --reload | Sabes levantar servidor con hot reload |
| /docs | Sabes probar endpoints desde el navegador |
| Respuestas JSON | Sabes retornar diccionarios que se serializan automáticamente |
Si alguno de estos puntos no te queda claro, revisa la cápsula correspondiente antes de continuar.
Recursos para el proyecto
- FastAPI Tutorial - First Steps - Referencia oficial para endpoints básicos
- FastAPI - Path Parameters - Documentación de path parameters
- FastAPI - Metadata and Docs - Personalización de documentación
- Uvicorn - Settings - Opciones de configuración del servidor
- HTTP Status Codes - MDN - Referencia de status codes
- JSON.org - Especificación del formato JSON