Módulo 5 · Arquitectura y código mantenible

Lección 26 — Manejo de errores centralizado

Un formato de error consistente para toda la API, no 40 respuestas distintas.

Publicada
En esta lección
  1. Ejercicio 1 — La taxonomía
  2. Ejercicio 2 — El handler
  3. Ejercicio 3 — Extra accionable
  4. Ejercicio 4 — El 500 sano
  5. Ejercicio 5 — El cliente que programa contra el contrato
  6. Entrega

Implementa el contrato de errores de TicketFlow. Sin solutions.md hasta entregar.

Ejercicio 1 — La taxonomía

  1. Enumera las excepciones de dominio de TicketFlow con su status: asiento ocupado (409), reserva expirada (410), evento agotado (409), pago rechazado (402 o 409 — decide y justifica), saldo de tarjeta regalo insuficiente (409 o 422 — decide), no autenticado (401, la maneja DRF).
  2. Para cada una escribe el problem+json completo (type, title, status, detail) tal como lo vería el cliente del front.

Ejercicio 2 — El handler

  1. Implementa problem_handler con to_problem() y problem_response(), conéctalo en settings y haz que los errores de validación de DRF salgan como problem+json (status 400, type .../validation-error, y errors con el dict de campo → mensajes).
  2. Escribe el test de contrato: POST a reserva con body inválido → 400 con Content-Type application/problem+json y type que termina en validation-error.
  3. Haz que una vista ANTERIOR (la que aún devuelve Response({"error":...})) se migre: borra su try/except, lanza la excepción de dominio, y verifica con el test que la respuesta no cambió (el test es la red de la 28).

Ejercicio 3 — Extra accionable

  1. Añade extra a SeatUnavailable(conflicting_seats) y a ReservationExpired(retry_after) — en este caso también el header Retry-After. ¿Dónde lo inyecta el handler?
  2. Test: reserva expirada → 410 con header Retry-After: 30 y body con retry_after: 30.

Ejercicio 4 — El 500 sano

  1. Fuerza un 500 (una vista que lanza ZeroDivisionError en un endpoint de test). Verifica: body problem+json genérico SIN stack, log con logger.exception y el trace_id presente.
  2. Añade la métrica http_5xx_total{path} (contador en memoria o Redis, la 46 la formaliza) incrementada en el handler. ¿Por qué en el handler y no en un middleware aparte? (pista: un solo lugar).
  3. Decide y escribe: ¿un 429 (rate limit de la 23) debe loggearse con warning o es ruido? ¿Y un 401?

Ejercicio 5 — El cliente que programa contra el contrato

  1. Escribe un test que consuma la API con un cliente HTTP fingido y aplique TODAS las reglas: cada error 4xx/5xx tiene type URI absoluto, title no vacío, status que coincide con el HTTP, trace_id presente en 5xx. Una sola función assert_problem(response).
  2. Pégala en 3 tests distintos (validación, dominio, 500). ¿Cuántas líneas te ahorró frente a escribir las assertions a mano en cada uno?

Entrega

Pega la taxonomía, el handler completo, el test de contrato y el test del 500. Después: Lección 27 — Configuración 12-factor.