Module 1: Setup and First API

Primer Endpoint, JSON y Docs

Descripción de la cápsula

En esta cápsula escribes tu primer endpoint real en FastAPI, retornas JSON (diccionarios y listas), y exploras la documentación automática que FastAPI genera sin una sola línea extra.

Aprenderás qué es una path operation, cómo los decoradores conectan rutas HTTP con funciones Python, cómo FastAPI serializa automáticamente tu return a JSON, y cómo usar /docs (Swagger UI) y /redoc para probar endpoints desde el navegador. Al terminar, tendrás una API con múltiples endpoints y documentación interactiva lista para usar.


Path operations: El concepto fundamental

Una path operation es la combinación de:

  1. Path (ruta): La URL del endpoint (/, /health, /items)
  2. Operation (operación): El verbo HTTP (GET, POST, etc.)
  3. Function (función): La función Python que se ejecuta
from fastapi import FastAPI

app = FastAPI()


# Path: "/"
# Operation: GET
# Function: root()
@app.get("/")
def root():
    return {"message": "Hello, World!"}

El decorador @app.get("/") le dice a FastAPI: "Registra la función root() como el handler para requests GET a la ruta /."


Tu primer endpoint GET

Código completo

# app/main.py
from fastapi import FastAPI

app = FastAPI()


@app.get("/")
def root():
    return {
        "message": "Welcome to my API",
        "version": "1.0.0"
    }

Levantar y probar

uvicorn app.main:app --reload

Abre http://127.0.0.1:8000 en tu navegador:

{
  "message": "Welcome to my API",
  "version": "1.0.0"
}

O con curl:

curl http://127.0.0.1:8000
curl -s http://127.0.0.1:8000 | python -m json.tool  # Formato bonito

Retornar JSON: Dicts y listas

FastAPI convierte automáticamente varios tipos de Python a JSON:

Tipo PythonJSON resultante
dictJSON object {}
listJSON array []
strJSON string
int, floatJSON number
boolJSON boolean
NoneJSON null

Ejemplos

@app.get("/dict")
def return_dict():
    return {"key": "value"}
# → {"key": "value"}

@app.get("/list")
def return_list():
    return [1, 2, 3, "four"]
# → [1, 2, 3, "four"]

@app.get("/nested")
def return_nested():
    return {
        "user": {"name": "Ana", "age": 25},
        "tags": ["python", "fastapi"]
    }

En la práctica, la mayoría de endpoints retornan diccionarios. Es la convención estándar para APIs REST.

Tipos no estándar

Si retornas un objeto custom (ej: instancia de una clase propia), FastAPI intentará serializarlo. Para tipos estándar (datetime, UUID) Pydantic los convierte automáticamente. Para clases propias, define un modelo Pydantic o implementa __json__ si es necesario. En este módulo solo usarás dicts y listas.


Múltiples endpoints

Agrega más rutas al mismo archivo:

from fastapi import FastAPI

app = FastAPI()


@app.get("/")
def root():
    return {"message": "Welcome to my API", "version": "1.0.0"}


@app.get("/health")
def health_check():
    return {"status": "healthy"}


@app.get("/about")
def about():
    return {
        "name": "FastAPI Fundamentals API",
        "description": "Learning FastAPI step by step",
        "python_version": "3.12"
    }

Cada decorador @app.get() registra una ruta diferente. FastAPI mantiene un router interno que mapea paths a funciones.

Probar todos

curl http://127.0.0.1:8000/
curl http://127.0.0.1:8000/health
curl http://127.0.0.1:8000/about

Documentación automática: /docs y /redoc

Swagger UI: /docs

Con el servidor corriendo, abre:

http://127.0.0.1:8000/docs

Verás una interfaz interactiva con todos tus endpoints. Para cada uno puedes:

  • Ver el método y la ruta
  • Hacer clic en "Try it out"
  • Ejecutar el request
  • Ver la respuesta (body, headers, status code)

Esto reemplaza curl y Postman para pruebas rápidas durante desarrollo.

ReDoc: /redoc

http://127.0.0.1:8000/redoc

ReDoc presenta la misma información con un diseño más orientado a documentación de referencia. No tiene "Try it out", pero es más legible para compartir con equipos.

Comparación rápida

Aspecto/docs (Swagger)/redoc
Try it outNo
Uso idealDesarrollo, testingDocumentación para otros
DiseñoFuncionalElegante

Personalizar metadata de la API

Puedes personalizar el título, descripción y versión que aparecen en la documentación:

from fastapi import FastAPI

app = FastAPI(
    title="FastAPI Fundamentals API",
    description="API de ejemplo para aprender FastAPI. Incluye endpoints GET y documentación automática.",
    version="1.0.0",
)


@app.get("/")
def root():
    return {"message": "Welcome"}

Refresca /docs. Ahora verás tu título y descripción en la cabecera.


Documentar endpoints individuales

Puedes agregar summary, description y tags a cada endpoint:

@app.get(
    "/health",
    summary="Health Check",
    description="Verifica que el servicio está corriendo. Útil para load balancers.",
    tags=["System"]
)
def health_check():
    return {"status": "healthy"}


@app.get(
    "/about",
    summary="About API",
    description="Metadata de la API: nombre, descripción, versión.",
    tags=["System"]
)
def about():
    return {"name": "FastAPI Fundamentals API", "version": "1.0.0"}

Los tags agrupan endpoints en secciones en /docs. Organiza por categoría: "System", "Items", "Users", etc.


OpenAPI: El estándar detrás

FastAPI genera automáticamente un schema OpenAPI. Puedes verlo en:

http://127.0.0.1:8000/openapi.json

Es un archivo JSON que describe tu API. Tanto /docs como /redoc lo leen para generar las interfaces. Tu código Python es la fuente de verdad — OpenAPI se genera a partir de él.

Flujo de generación

Tu código Python (decoradores, type hints, docstrings)
    ↓ FastAPI analiza y construye el schema
openapi.json (schema OpenAPI 3.1)
    ↓ Swagger UI y ReDoc lo interpretan
Interfaces /docs y /redoc

Cada vez que agregas o modificas un endpoint, el schema se actualiza. No hay desincronización entre código y documentación.


Docstrings como documentación

Puedes usar docstrings en lugar de (o además de) description en el decorador:

@app.get("/health", tags=["System"])
def health_check():
    """
    Verifica que el servicio está corriendo.
    Útil para load balancers y monitoreo.
    """
    return {"status": "healthy"}

FastAPI renderiza el docstring como Markdown en la documentación. Si defines tanto description como docstring, el docstring tiene prioridad.


Código completo del ejemplo

# app/main.py
from fastapi import FastAPI

app = FastAPI(
    title="FastAPI Fundamentals API",
    description="API de ejemplo con múltiples endpoints GET.",
    version="1.0.0",
)


@app.get("/", tags=["General"])
def root():
    return {"message": "Welcome to my API", "version": "1.0.0"}


@app.get("/health", tags=["System"], summary="Health Check")
def health_check():
    return {"status": "healthy"}


@app.get("/about", tags=["System"], summary="About")
def about():
    return {
        "name": "FastAPI Fundamentals API",
        "description": "Learning FastAPI step by step"
    }

Desactivar o customizar URLs de documentación

En producción a veces se desactiva la documentación por seguridad:

app = FastAPI(
    docs_url=None,   # Desactiva /docs
    redoc_url=None,  # Desactiva /redoc
)

O cambiar las rutas:

app = FastAPI(
    docs_url="/api-docs",
    redoc_url="/api-reference",
)

Para desarrollo, déjalas activas. Son tu herramienta principal de pruebas.


Troubleshooting

Problema 1: 404 Not Found en un endpoint

Causa: La URL no coincide exactamente con la ruta definida.

Solución: Las rutas son case-sensitive y no incluyen trailing slash por defecto:

@app.get("/health")
# ✅ http://127.0.0.1:8000/health
# ❌ http://127.0.0.1:8000/Health
# ❌ http://127.0.0.1:8000/health/

Problema 2: Un endpoint no aparece en /docs

Causa: Error de sintaxis en el decorador o en la función.

Solución:

# ❌ Mal — falta ruta
@app.get
def root():
    return {"message": "Hello"}

# ✅ Bien
@app.get("/")
def root():
    return {"message": "Hello"}

Verifica que no hay errores en la terminal de uvicorn.

Problema 3: /docs muestra página en blanco

Causa: Problemas cargando assets (CDN bloqueado, sin internet).

Solución: Verifica conexión a internet. Swagger UI carga recursos desde un CDN. En entornos restringidos puede requerir configuración adicional.

Problema 4: La descripción no se muestra

Causa: Formato incorrecto en description o docstring.

Solución: Usa strings válidos:

@app.get("/health", description="Verifica que el servicio está activo.")
def health_check():
    return {"status": "healthy"}

Ejercicios

Ejercicio 1: Endpoint de timestamp (Fácil)

Crea un endpoint GET en /time que retorne la fecha y hora actual del servidor en formato JSON.

Ver solución
from datetime import datetime
from fastapi import FastAPI

app = FastAPI()


@app.get("/time")
def current_time():
    now = datetime.now()
    return {
        "date": now.strftime("%Y-%m-%d"),
        "time": now.strftime("%H:%M:%S"),
        "timestamp": now.isoformat()
    }

Explicación: datetime.now() obtiene la fecha/hora actual. strftime la formatea. FastAPI serializa el dict a JSON.

Ejercicio 2: Retornar una lista (Fácil)

Crea un endpoint GET en /items que retorne una lista de 3 items con id y name. Usa una lista de diccionarios.

Ver solución
@app.get("/items")
def list_items():
    return [
        {"id": 1, "name": "Item 1"},
        {"id": 2, "name": "Item 2"},
        {"id": 3, "name": "Item 3"},
    ]

Explicación: FastAPI convierte listas de dicts a arrays JSON automáticamente. La respuesta será [{...}, {...}, {...}].

Ejercicio 3: Personalizar documentación (Medio)

Configura tu aplicación con título "Mi Primera API", versión "0.1.0", y una descripción. Agrega tags "General" y "System" a tus endpoints. Verifica en /docs que todo se muestra correctamente.

Ver solución
from fastapi import FastAPI

app = FastAPI(
    title="Mi Primera API",
    description="API de aprendizaje con FastAPI. Endpoints básicos y documentación.",
    version="0.1.0",
)


@app.get("/", tags=["General"])
def root():
    return {"message": "Welcome"}


@app.get("/health", tags=["System"], summary="Health Check")
def health_check():
    return {"status": "healthy"}

Explicación: title, description y version aparecen en la cabecera de Swagger. Los tags agrupan los endpoints en secciones.

Ejercicio 4: Probar con "Try it out" (Fácil)

Abre /docs, haz clic en un endpoint, "Try it out", "Execute". Anota qué información te muestra: Request URL, Response body, Response code. Compara con lo que verías usando curl.

Ver solución

En /docs con Try it out:

  • Curl: El comando curl equivalente (puedes copiarlo)
  • Request URL: La URL completa usada
  • Response body: El JSON de la respuesta
  • Response code: 200, 404, etc.

Con curl: Obtienes lo mismo pero manualmente. "Try it out" te da todo en una interfaz visual y genera el curl por ti.

Explicación: Swagger UI es una herramienta de desarrollo integrada. Para pruebas rápidas durante desarrollo, suele ser más cómoda que curl.

Ejercicio 5: API con 4 endpoints (Medio)

Crea una API con exactamente 4 endpoints: /, /health, /about, /items. El último debe retornar una lista vacía o con un item de ejemplo. Usa tags para organizar. Verifica que los 4 aparecen en /docs y funcionan.

Ver solución
from fastapi import FastAPI

app = FastAPI(title="Mi API", version="1.0.0")


@app.get("/", tags=["General"])
def root():
    return {"message": "Hello, World!"}


@app.get("/health", tags=["System"])
def health():
    return {"status": "healthy"}


@app.get("/about", tags=["System"])
def about():
    return {"name": "Mi API", "version": "1.0.0"}


@app.get("/items", tags=["Items"])
def items():
    return []

Explicación: Cada @app.get() registra un endpoint. /items retorna una lista vacía [] que se serializa a [] en JSON.

Ejercicio 6: openapi.json (Medio)

Abre http://127.0.0.1:8000/openapi.json en tu navegador. Busca la sección paths. ¿Cuántas rutas hay? ¿Qué información tiene cada una?

Ver solución

En paths verás un objeto donde cada key es una ruta (/, /health, etc.). Cada ruta tiene un objeto con los métodos permitidos (get, post, etc.) y sus detalles (summary, parameters, responses).

Contar rutas: Cuenta las keys en paths. Si tienes 4 endpoints, habrá 4 keys.

Información típica:

  • summary: Título del endpoint
  • responses: Códigos de respuesta (200, 422, etc.)
  • operationId: Identificador único

Explicación: openapi.json es el schema que /docs y /redoc interpretan. Es la representación estándar de tu API en formato legible por máquinas.


Flujo completo: De código a respuesta

Cuando escribes:

@app.get("/health")
def health_check():
    return {"status": "healthy"}

Y un cliente hace GET /health:

  1. uvicorn recibe el request
  2. FastAPI busca la ruta en el router
  3. Encuentra health_check asociada a GET /health
  4. Ejecuta la función (sin argumentos en este caso)
  5. Recibe {"status": "healthy"}
  6. Serializa a JSON con Content-Type: application/json
  7. Retorna HTTP 200 con el body

Todo esto ocurre en milisegundos. Tú solo defines la función; el framework maneja el resto.


Resumen

  • ✅ Una path operation combina ruta + verbo HTTP + función Python
  • @app.get("/ruta") registra un endpoint GET
  • ✅ Retornar diccionarios o listas se serializa automáticamente a JSON
  • /docs (Swagger UI) permite probar endpoints con "Try it out"
  • /redoc ofrece documentación de referencia
  • ✅ Puedes personalizar metadata (title, description, version) y documentar cada endpoint (summary, tags)
  • openapi.json es el schema que alimenta ambas interfaces

Próxima cápsula: Proyecto Hello World API — integrarás todo en una API con 4 endpoints, código completo y rúbrica de evaluación.


Recursos Adicionales

  1. FastAPI - First Steps - Tutorial oficial
  2. FastAPI - Metadata - Personalización de documentación
  3. Swagger UI - Herramienta detrás de /docs
  4. ReDoc - Herramienta detrás de /redoc
  5. OpenAPI 3.1 - Especificación OpenAPI
  6. JSON.org - Formato JSON

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