Módulo 3 · Diseño de APIs

Lección 13 — REST bien hecho

Recursos, verbos, errores consistentes, paginación, filtros y ordenación.

Publicada
En esta lección
  1. Ejercicio 1 — La superficie completa
  2. Ejercicio 2 — Handler RFC 7807
  3. Ejercicio 3 — Paginación de verdad
  4. Ejercicio 4 — UUID público
  5. Ejercicio 5 — El contrato de headers: ETag, Vary y Cabeceras de API
  6. Entrega

DRF en tu proyecto. No mires solutions.md hasta entregar.

Ejercicio 1 — La superficie completa

  1. Escribe la tabla de rutas de TicketFlow completa (como la de la lección) incluyendo: registro/login (adelanto de la 18), eventos, asientos, disponibilidad, reservas, pagos, webhook, tarjetas regalo.
  2. Para cada ruta: verbo(s), auth necesaria (público / dueño / organizador / sistema), y código de éxito.
  3. Crítica la tuya: ¿algún verbo en la ruta? ¿algún anidamiento >1 nivel? ¿alguno sin plural?

Ejercicio 2 — Handler RFC 7807

  1. Implementa custom_exception_handler(exc, context) en DRF que produzca el formato de la lección para: ValidationError (400), Http404 (404), PermissionDenied (403), tu excepción de dominio (409/422).
  2. Define DomainError(code, status, title, detail) y lánzala desde reservar() de la 10 cuando el asiento esté ocupado; verifica el cuerpo JSON resultante.
  3. ¿Qué pasa con Detail: None en errores sin detalle? Decide el campo mínimo obligatorio y justifícalo.

Ejercicio 3 — Paginación de verdad

  1. Configura cursor pagination en el listado de eventos y offset en el panel de admin (settings de DRF: dos paginadores). Verifica las respuestas (next, previous, results).
  2. Genera 500 eventos y compara ?page=999 (offset) vs cursor profundo: mide tiempos con EXPLAIN ANALYZE detrás.
  3. Añade filtros con django-filter: state, starts_after, ordering con whitelist (solo starts_at, title, -starts_at).

Ejercicio 4 — UUID público

  1. Añade uuid = UUIDField(default=uuid4, unique=True, editable=False) a Event y Reservation (migración segura de la 11).
  2. Cambia lookup a lookup_field = "uuid" en tus viewsets y serializers. Verifica que /api/events/{entero}/ devuelve 404 y el UUID 200.
  3. ¿Debería la reserva del usuario A ser enumerable por el usuario B con el UUID correcto? ¿Qué capa lo impide (adelanto 21)?

Ejercicio 5 — El contrato de headers: ETag, Vary y Cabeceras de API

  1. Añade el ETag al detalle de evento (con el updated_at del recurso, la 38) y verifica: segunda petición con If-None-Match → 304 vacío. ¿Qué ahorra tu ancho de banda el día del pico?
  2. Añade Vary: Accept-Encoding al proxy o a la respuesta y comprueba con curl que el 304 distingue cliente gzip de cliente plano (39).
  3. Cabeceras de la plataforma: añade a TODAS las respuestas X-Request-ID (el trace_id de la 45), X-RateLimit-Remaining (23) y X-Content-Type-Options: nosniff. Test de contrato: las tres presentes en un 200 y en un 409.

Entrega

Pega rutas, código del handler y salidas. Después: Lección 14 — Idempotencia y versionado.