Módulo 3 · Diseño de APIs

Lección 14 — Idempotencia y versionado

Compatibilidad hacia atrás y la Idempotency-Key que evita cobrar dos veces.

Publicada
En esta lección
  1. Ejercicio 1 — El cobro doble, reproducido
  2. Ejercicio 2 — Idempotency-Key real
  3. Ejercicio 3 — Los idempotentes por diseño
  4. Ejercicio 4 — Webhook idempotente
  5. Ejercicio 5 — Versionado sin romper
  6. Entrega

DRF + tu BD. No mires solutions.md hasta entregar.

Ejercicio 1 — El cobro doble, reproducido

  1. Simula el reintento: en shell, llama dos veces a la creación de pago de una misma reserva (o curl dos veces). ¿Dos pagos? (la UNIQUE de idempotency_key debe impedirlo si generaste la clave igual... ¿o estás generando uuid4 en cada POST? Anota lo que pase).
  2. Discute: ¿dónde está el bug semántico — la BD rechaza el segundo, pero ¿con qué status responde tu API hoy?

Ejercicio 2 — Idempotency-Key real

  1. Crea el modelo IdempotencyKey(key PK, request_hash, status, body JSONB, created_at) + migración segura (11).
  2. Implementa el mecanismo (decorador o helper en la vista de pagos): 1ª vez procesa y guarda; 2ª vez con mismo cuerpo devuelve lo guardado; mismo key + cuerpo distinto → 422.
  3. Demuéstralo con curl: mismo POST dos veces con la misma Idempotency-Key → misma respuesta y UN solo Payment en BD.

Ejercicio 3 — Los idempotentes por diseño

  1. Haz que DELETE /reservations/{uuid}/ sea idempotente: cancelar dos veces → 204 ambas (el cancel() de la 00b ya devuelve False; conecta).
  2. PUT /api/events/{uuid}/ con reemplazo completo: demuestra que enviar el mismo PUT dos veces deja el mismo estado (y que PATCH con {"price": "+2"} dos veces NO es idempotente).

Ejercicio 4 — Webhook idempotente

  1. En tu handler del webhook (simulado): busca el pago por el event_id de la pasarela antes de crear; si existe, responde 200 sin reprocesar. Demuéstralo con el mismo payload tres veces.
  2. ¿Qué status le respondes a la pasarela en el reintento duplicado y por qué NUNCA 4xx ahí?

Ejercicio 5 — Versionado sin romper

  1. Activa URLPathVersioning (o rutas manuales /api/v1/) y duplica un endpoint con un cambio rompedor (p. ej. v2 devuelve starts_at ISO con zona y v1 naive).
  2. Documenta la deprecación: cabecera Deprecation: true en v1 cuando exista uso, y escribe la consulta de métrica que mediría el tránsito de clientes v1→v2 (qué contaría: por endpoint y por día).

Entrega

Pega código y curl outputs. Después: Lección 15 — Validación y contratos con OpenAPI.