Module 3: Request and Response

Introducción al Módulo 3: Request y Response

Descripción

Tu Books API del Módulo 2 funciona: puedes crear libros, listarlos, actualizarlos y eliminarlos. Pero tiene un problema evidente — no puedes filtrar. Si tienes 500 libros y quieres solo los de ciencia ficción publicados después de 2010, tu única opción es hacer GET a todos y filtrar del lado del cliente. Tampoco puedes paginar resultados, buscar por texto en el título, ni decirle a la API exactamente qué datos necesitas. En este módulo vas a resolver eso.

Aquí aprendes a manejar datos de entrada de forma profesional. Hasta ahora, tus endpoints reciben un book_id en la URL y un JSON en el body — nada más. Pero un request HTTP tiene tres fuentes de datos: la URL (path), los query parameters (después del ?), y el body. FastAPI puede extraer, validar y convertir datos de las tres fuentes automáticamente, usando nada más que type hints y funciones especiales como Query(), Path() y Body(). Al terminar este módulo, tus endpoints recibirán datos de múltiples fuentes y rechazarán automáticamente los que no cumplan tus reglas.

La diferencia entre tu API actual y lo que construirás es la diferencia entre "funciona" y "funciona bien." Una API que no filtra obliga al cliente a descargar todo. Una API que no valida parámetros acepta basura silenciosamente. Una API que no pagina se cae con datasets grandes. Después de este módulo, tu API hace las tres cosas.


¿Dónde estamos en la guía?

Estás en el Módulo 3 de 6 de la guía FastAPI Fundamentals:

Módulo 1: Setup y Primera API ✅ (completado)
    → Instalación, uvicorn, endpoints GET, documentación automática

Módulo 2: Path Operations ✅ (completado)
    → GET, POST, PUT, PATCH, DELETE — CRUD completo

Módulo 3: Request y Response ← ESTÁS AQUÍ
    → Query params, path params avanzados, body, headers, cookies

Módulo 4: Pydantic y Validación
Módulo 5: Error Handling y CORS
Módulo 6: Proyecto Final — To-Do List API

Progresión acumulativa

Cada módulo agrega una capa sobre el anterior:

Módulo 1: Servidor corriendo + endpoints GET básicos
    ↓ (base)
Módulo 2: + CRUD completo (POST, PUT, PATCH, DELETE)
    ↓ (operaciones)
Módulo 3: + Parámetros avanzados, filtros, paginación  ← AQUÍ
    ↓ (datos de entrada)
Módulo 4: + Validación con Pydantic models
    ↓ (datos estructurados)
Módulo 5: + Error handling + CORS
    ↓ (robustez)
Módulo 6: To-Do List API (integración total)

El Módulo 2 te dio las operaciones. El Módulo 3 te da el control fino sobre qué datos entran y cómo los recibes.


Lo que ya dominas vs Lo nuevo

Lo que ya dominas

De los Módulos 1 y 2 traes:

  • ✅ Virtual environment con FastAPI y uvicorn funcionando
  • ✅ Estructura de proyecto app/main.py
  • ✅ Endpoints GET, POST, PUT, PATCH, DELETE
  • ✅ Path parameters con type hints (book_id: int)
  • ✅ Request body como dict (POST y PUT)
  • ✅ Status codes básicos (200, 201, 204)
  • ✅ Datos en memoria (lista de diccionarios)
  • ✅ Probar endpoints en /docs

Lo nuevo de este módulo

  • 🆕 Query parameters con valores por defecto
  • 🆕 Optional para parámetros opcionales
  • 🆕 Query() — validación y metadata para query params
  • 🆕 Path() — validación y metadata para path params
  • 🆕 Body() — control explícito del request body
  • 🆕 Header() y Cookie() — leer headers y cookies del request
  • 🆕 Combinar múltiples tipos de parámetros en un endpoint
  • 🆕 Error 422 (Unprocessable Entity) — validación automática
  • 🆕 Paginación con skip y limit
  • 🆕 Filtros por campos específicos

De "funciona" a "funciona bien"

AspectoMódulo 2 (tu API actual)Módulo 3 (tu API mejorada)
Listar librosGET /books → todosGET /books?genre=fiction&limit=10 → filtrado
BuscarNo existeGET /books?search=quijote → por texto
PaginarNo existeGET /books?skip=20&limit=10 → página 3
Validar pathbook_id: int (solo tipo)Path(ge=1, description="...") (tipo + rango)
Documentación paramsAutomática pero básicaDescripciones, ejemplos, constraints

Objetivo del módulo

Al completar este módulo serás capaz de:

  • ✅ Agregar query parameters a tus endpoints con valores por defecto
  • ✅ Usar Optional para parámetros que el cliente puede omitir
  • ✅ Implementar filtros por campo (genre, year, available)
  • ✅ Implementar búsqueda por texto en campos string
  • ✅ Implementar paginación con skip y limit
  • ✅ Usar Query(), Path() y Body() para validar y documentar parámetros
  • ✅ Agregar constraints como ge, le, min_length, max_length
  • ✅ Leer headers y cookies del request con Header() y Cookie()
  • ✅ Combinar path params, query params y body en un mismo endpoint
  • ✅ Entender y aprovechar el error 422 como feature de protección
  • ✅ Estructurar respuestas JSON consistentes

Prerequisitos

Para este módulo necesitas:

  • Módulo 2 completado — CRUD de Books API funcionando
  • Tu proyecto con datos de libros — La lista de diccionarios con al menos 5 libros
  • uvicorn corriendo con --reload — Para probar cambios en tiempo real

Verificación rápida

cd fastapi-fundamentals
source venv/bin/activate
uvicorn app.main:app --reload

Abre http://localhost:8000/docs y verifica que puedes:

  1. Listar libros con GET /books
  2. Crear un libro con POST /books
  3. Obtener un libro por ID con GET /books/{book_id}

Si eso funciona, estás listo para el Módulo 3.

¿Qué pasa si no cumples algún prerequisito?

Prerequisito faltanteQué hacer
No hiciste el Módulo 2Completa las cápsulas 02-05 del Módulo 2 primero
Tu Books API no levantaRevisa errores de importación y verifica que FastAPI está instalado
No tienes datos de librosAgrega al menos 5 libros con campos id, title, author, year, genre, available

Roadmap del módulo

CápsulaTemaQué aprenderás
01Introducción (esta cápsula)Contexto, fuentes de datos, el error 422, roadmap
02Query parametersFiltros, paginación, defaults, Optional, múltiples params
03Path(), Query(), Body()Funciones avanzadas, validación, constraints, metadata, combinar
04Headers, cookies y respuestasHeader(), Cookie(), estructura de response consistente
05Proyecto: Books API con filtrosFiltros por genre/year/available, búsqueda por texto, paginación

Flujo de aprendizaje

Primero aprenderás a recibir query parameters: parámetros después del ? en la URL que permiten filtrar, buscar y paginar sin cambiar las rutas existentes (Cápsula 02). Después profundizarás en Query(), Path() y Body(), las funciones de FastAPI que agregan validación, constraints y documentación a tus parámetros (Cápsula 03). Luego expandirás a Header() y Cookie() para leer datos del request que no vienen en la URL ni en el body, y aprenderás a estructurar respuestas consistentes (Cápsula 04). Al final, integrarás todo en tu Books API: filtros por género, año y disponibilidad, búsqueda por texto en título, y paginación con skip/limit (Cápsula 05).

La progresión es: filtrar → validar → expandir → integrar.

Detalle por cápsula

Cápsula 02 — Query parameters: Agregarás parámetros de filtrado a tu endpoint GET /books. Aprenderás que FastAPI detecta automáticamente que un parámetro de función que no está en la URL es un query parameter. Implementarás skip y limit para paginación, genre y year para filtros, y search para búsqueda por texto. Usarás Optional para parámetros que el cliente puede omitir.

Cápsula 03 — Path(), Query(), Body() avanzado: Pasarás de declarar parámetros simples a usar las funciones Query(), Path() y Body() para agregar validación (rangos numéricos, longitudes de string), metadata (descripción, ejemplo, título), y constraints. Aprenderás a combinar múltiples tipos de parámetros en un mismo endpoint.

Cápsula 04 — Headers, cookies y respuestas: Descubrirás Header() y Cookie(), que permiten leer datos del request más allá de la URL y el body. Aprenderás a estructurar respuestas JSON consistentes con metadata (total de resultados, página actual). Verás cómo FastAPI maneja la conversión automática de nombres (X-Custom-Headerx_custom_header).

Cápsula 05 — Proyecto Books API con filtros: Tu Books API del Módulo 2 se transforma. El endpoint GET /books ahora acepta genre, year, available, search, skip y limit. Cada parámetro tiene validación con Query(). Los filtros se combinan: puedes pedir libros de ciencia ficción publicados después de 2000 que estén disponibles, limitado a 5 resultados.


Tres fuentes de datos en un request HTTP

Antes de entrar a las cápsulas técnicas, necesitas entender de dónde vienen los datos en un request HTTP. Son tres fuentes, y FastAPI las maneja todas automáticamente.

1. Path parameters — datos en la URL

GET /books/42
            ──
            └── path parameter: book_id = 42

El dato está embebido en la ruta misma. Ya los usas desde el Módulo 1: @app.get("/books/{book_id}"). FastAPI sabe que book_id viene del path porque está entre llaves en la ruta.

2. Query parameters — datos después del ?

GET /books?genre=fiction&limit=10&skip=0
           ─────────────────────────────
           └── query parameters:
               genre = "fiction"
               limit = 10
               skip = 0

Los query parameters van después del signo ? en la URL, separados por &. Son ideales para filtros, ordenamiento y paginación porque no cambian la ruta — sigues accediendo a /books, solo que con condiciones.

3. Request body — datos en el payload JSON

POST /books
Content-Type: application/json

{
    "title": "El Principito",
    "author": "Antoine de Saint-Exupéry",
    "year": 1943
}

El body es el cuerpo del request, normalmente JSON. Se usa con POST, PUT y PATCH para enviar datos complejos. Ya lo usas: cuando haces POST en el Módulo 2, el JSON que envías es el request body.

¿Cómo sabe FastAPI de dónde tomar cada parámetro?

La regla es elegante:

@app.get("/books/{book_id}")
def get_books(book_id: int, genre: str = None, limit: int = 10):
    ...
  • book_id → aparece en la ruta ({book_id}) → path parameter
  • genre → no está en la ruta, tipo simple → query parameter
  • limit → no está en la ruta, tipo simple → query parameter

FastAPI analiza la firma de tu función y la ruta del decorador. Si un parámetro tiene el mismo nombre que algo entre llaves en la ruta, es un path parameter. Si no está en la ruta y es un tipo simple (str, int, float, bool), es un query parameter. Si es un tipo complejo (dict, Pydantic model), es un body parameter.

No necesitas configurar nada explícitamente en la mayoría de los casos — los type hints hacen el trabajo.

Las tres fuentes en un solo request

Un request puede usar las tres fuentes simultáneamente:

PATCH /books/42?notify=true
               ────────────
Body: {"title": "Nuevo título"}

book_id = 42           ← path
notify = true          ← query
title = "Nuevo título" ← body

En la Cápsula 03 aprenderás a combinar las tres en un solo endpoint.


Type hints como contrato

En el Módulo 1 usaste type hints para que FastAPI sepa que book_id es un int. Pero los type hints en FastAPI son mucho más que documentación — son un contrato entre tu API y el mundo exterior.

¿Qué hace FastAPI con tus type hints?

Tres cosas automáticamente:

1. Conversión: Si defines limit: int y el cliente envía "10" (string en la URL), FastAPI convierte "10" a 10 (entero). No necesitas escribir int(request.query_params["limit"]).

2. Validación: Si defines book_id: int y el cliente envía "abc", FastAPI rechaza el request con un error 422 antes de que tu función se ejecute. Tu código nunca ve datos inválidos.

3. Documentación: Si defines genre: str = None, /docs muestra un campo "genre" de tipo string, opcional, con valor por defecto None. El cliente sabe exactamente qué puede enviar.

El contrato en acción

@app.get("/books/{book_id}")
def get_book(book_id: int):
    ...

Este type hint book_id: int le dice al mundo:

  • "Este endpoint requiere un entero en la URL"
  • "Si envías algo que no es entero, te rechazo"
  • "La documentación dice que es un entero obligatorio"

No escribiste validación. No escribiste documentación. No escribiste conversión. Todo lo genera FastAPI a partir de : int.

Escalando el contrato

Con las funciones Query(), Path() y Body() del Módulo 3, el contrato se hace más rico:

@app.get("/books")
def list_books(
    limit: int = Query(default=10, ge=1, le=100, description="Resultados por página")
):
    ...

Ahora el contrato dice: "limit es un entero, opcional, por defecto 10, mínimo 1, máximo 100, y sirve para controlar resultados por página." Todo eso en una línea.


El error 422: Unprocessable Entity

Cuando pruebes tus endpoints con parámetros inválidos, vas a ver un error que quizás no conoces: el 422 Unprocessable Entity. Antes de que pienses que algo está roto, entiende esto: el 422 es una feature, no un bug.

¿Cuándo aparece?

El 422 aparece cuando FastAPI no puede procesar los datos que recibió porque no cumplen con el contrato de tipos:

GET /books/abc
→ 422: book_id debe ser int, recibí "abc"

GET /books?limit=-5  (con Query(ge=1))
→ 422: limit debe ser >= 1, recibí -5

POST /books  (body vacío cuando se requiere)
→ 422: falta el campo requerido "title"

¿Por qué es una feature?

Sin validación automática, tu código recibiría "abc" como book_id y se rompería dentro de tu función — probablemente con un error 500 (Internal Server Error) poco descriptivo. El 422 intercepta el problema antes de que tu código se ejecute.

Compara:

Sin validación (API frágil):
    Cliente envía "abc" → Tu código crashea → Error 500 genérico
    El cliente no sabe qué hizo mal

Con FastAPI (API robusta):
    Cliente envía "abc" → FastAPI rechaza → Error 422 descriptivo
    El cliente sabe exactamente qué corregir

Anatomía de un error 422

FastAPI retorna errores 422 con un formato consistente y descriptivo:

{
    "detail": [
        {
            "type": "int_parsing",
            "loc": ["path", "book_id"],
            "msg": "Input should be a valid integer, unable to parse string as an integer",
            "input": "abc"
        }
    ]
}

Cada error te dice:

  • type — Qué tipo de error ocurrió
  • loc — Dónde está el problema (path, query, body + nombre del campo)
  • msg — Descripción legible del error
  • input — Qué valor envió el cliente

El cliente puede leer esto y corregir su request automáticamente. No necesitas escribir ni una línea de código para que esto funcione.

El 422 en tu workflow de desarrollo

Cuando estés construyendo tu Books API con filtros, vas a provocar errores 422 intencionalmente para verificar que la validación funciona. Si defines limit: int = Query(ge=1, le=100) y envías limit=0, esperas un 422. Si no lo recibes, algo está mal en tu configuración.

El 422 es tu red de seguridad. Abraza el 422.


¿Qué NO se cubre en este módulo?

Es importante saber los límites para no buscar algo que viene después:

  • Pydantic models — Se cubren en Módulo 4. Aquí defines parámetros directamente en la función, sin crear clases de validación
  • HTTPException personalizado — Se cubre en Módulo 5. Aquí solo ves el 422 automático, no creas tus propios errores
  • Response models — Se cubren en Módulo 4 con Pydantic
  • WebSockets — Fuera del scope de esta guía
  • File uploads — Fuera del scope de esta guía
  • Form data — Esta guía trabaja solo con JSON

¿Por qué estos límites?

  • Pydantic viene después porque primero necesitas entender cómo FastAPI maneja parámetros individuales. Query(ge=1) es la base para entender Field(ge=1) en Pydantic
  • HTTPException viene después porque primero experimentas los errores automáticos (422). Cuando veas qué pasa cuando buscas un libro que no existe (y no obtienes un 404 descriptivo), entenderás por qué HTTPException importa
  • Response models necesitan Pydantic — sin modelos no hay response models

Cada límite es intencional: primero dominas parámetros sueltos, luego los agrupas en modelos (M4), luego controlas los errores (M5).


Conexión con el proyecto

Tu Books API del Módulo 2 va a evolucionar significativamente en este módulo. Así se ve la transformación:

Antes (Módulo 2)

GET /books              → Retorna TODOS los libros (siempre)
GET /books/{book_id}    → Retorna un libro por ID
POST /books             → Crea un libro
PUT /books/{book_id}    → Actualiza completo
PATCH /books/{book_id}  → Actualiza parcial
DELETE /books/{book_id} → Elimina

Después (Módulo 3)

GET /books?genre=fiction&year=2010&available=true&search=quijote&skip=0&limit=10
    → Filtra por género, año, disponibilidad
    → Busca texto en el título
    → Pagina resultados con skip/limit
    → Cada parámetro es opcional con valor por defecto
    → Cada parámetro tiene validación automática

GET /books/{book_id}
    → book_id validado con Path(ge=1, description="ID del libro")

POST /books
    → Body validado con constraints en campos

La ruta no cambia — /books sigue siendo /books. Lo que cambia es la riqueza de datos que el endpoint puede recibir y procesar. Esa es la filosofía de los query parameters: agregar capacidad sin modificar la estructura de rutas.

La Books API como proyecto evolutivo

Módulo 1: Hello World API (esqueleto vacío)
    ↓
Módulo 2: Books API con CRUD (operaciones básicas)
    ↓
Módulo 3: Books API con filtros y validación de params  ← AQUÍ
    ↓
Módulo 4: Books API con Pydantic (modelos y validación de body)
    ↓
Módulo 5: Books API con error handling y CORS
    ↓
Módulo 6: To-Do List API (proyecto nuevo integrando todo)

Cómo usar esta guía en el Módulo 3

Enfoque práctico

Cada cápsula incluye código que debes escribir y probar. El ciclo de este módulo es:

  1. Lee la explicación — Entiende el concepto antes de escribir
  2. Escribe el código — Agrega los parámetros a tus endpoints existentes
  3. Prueba en /docs — Los query parameters aparecen como campos en la interfaz
  4. Prueba combinaciones — ¿Qué pasa si combinas filtros? ¿Si omites uno?
  5. Provoca errores 422 — Envía datos inválidos intencionalmente para ver la validación

Tiempo estimado

  • Cápsula de introducción (esta): 15-20 minutos
  • Cápsulas técnicas (02-04): 25-40 minutos cada una
  • Proyecto (05): 40-60 minutos
  • Total Módulo 3: 2-3 horas

Tip de testing

Cada vez que agregues un parámetro, abre /docs y observa cómo la documentación se actualiza automáticamente. Los query parameters aparecen como campos con tipo, valor por defecto, y descripción (si usas Query(description="...")). Esa documentación la genera FastAPI gratis — y es exactamente lo que un consumidor de tu API necesita para saber cómo usarla.


Evidencia de éxito

Al terminar este módulo (las 5 cápsulas), sabrás que tuviste éxito si:

  • ✅ Tu endpoint GET /books acepta query parameters para filtrar por genre, year y available
  • ✅ Puedes buscar libros por texto en el título con un parámetro search
  • ✅ La paginación funciona: skip=0&limit=5 retorna los primeros 5, skip=5&limit=5 los siguientes 5
  • ✅ Los parámetros opcionales tienen valores por defecto sensatos
  • ✅ Si envías limit=0 o limit=-5, recibes un error 422 (no un resultado vacío o roto)
  • ✅ Path parameters tienen validación con Path() (ej: book_id debe ser >= 1)
  • ✅ La documentación en /docs muestra descripciones, tipos y constraints para cada parámetro
  • ✅ Puedes combinar filtros: genre=fiction&year=2000&limit=5 funciona correctamente
  • ✅ Entiendes la diferencia entre path params, query params y body params

Resumen

  • Este es el Módulo 3 de 6, enfocado en manejar datos de entrada de forma profesional
  • Los requests HTTP tienen tres fuentes de datos: path (URL), query (después del ?) y body (JSON)
  • FastAPI determina automáticamente de dónde tomar cada parámetro usando type hints y la definición de ruta
  • Los type hints son un contrato: convierten, validan y documentan automáticamente
  • Query(), Path() y Body() agregan constraints, metadata y validación avanzada
  • Header() y Cookie() permiten leer datos del request más allá de URL y body
  • El error 422 es una feature de protección, no un bug — rechaza datos inválidos antes de que tu código corra
  • Tu Books API pasará de "listar todo" a filtrar, buscar y paginar con parámetros validados
  • No se cubre Pydantic models (M4), HTTPException personalizado (M5), ni WebSockets
  • La progresión es: filtrar → validar → expandir → integrar

Recursos adicionales

  1. FastAPI - Query Parameters - Tutorial oficial de query parameters con ejemplos
  2. FastAPI - Path Parameters and Numeric Validations - Path() con validaciones numéricas
  3. FastAPI - Query Parameters and String Validations - Query() con validaciones de string
  4. FastAPI - Request Body - Cómo FastAPI maneja request bodies con type hints
  5. FastAPI - Header Parameters - Header() y convenciones de nombres
  6. FastAPI - Cookie Parameters - Cookie() para leer cookies del request

Siguiente cápsula: Query Parameters — Agregarás filtros, búsqueda y paginación a tu Books API usando parámetros después del ? en la URL.