DRF + your DB. Do not look at solutions.md before submitting.
Exercise 1 — The double charge, reproduced
- Simulate the retry: in the shell, call the payment creation for the same reservation twice (or curl twice). Two payments? (the idempotency_key UNIQUE should prevent it if you generated the key the same way... or are you generating a uuid4 on every POST? Note what happens).
- Discuss: where is the semantic bug — the DB rejects the second one, but with what status does your API answer today?
Exercise 2 — A real Idempotency-Key
- Create the model
IdempotencyKey(key PK, request_hash, status, body JSONB, created_at)+ a safe migration (11). - Implement the mechanism (decorator or helper on the payments view): 1st time processes and stores; 2nd time with the same body returns the stored one; same key + different body → 422.
- Demonstrate with curl: the same POST twice with the same
Idempotency-Key→ the same response and ONE Payment in the DB.
Exercise 3 — Idempotent by design
- Make
DELETE /reservations/{uuid}/idempotent: cancelling twice → 204 both times (00b'scancel()already returns False; connect the dots). PUT /api/events/{uuid}/with full replacement: demonstrate that sending the same PUT twice leaves the same state (and that PATCH with{"price": "+2"}twice is NOT idempotent).
Exercise 4 — Idempotent webhook
- In your (simulated) webhook handler: look up the payment by the gateway's
event_idbefore creating; if it exists, answer 200 without reprocessing. Demonstrate with the same payload three times. - What status do you answer to the gateway on the duplicated retry, and why NEVER 4xx there?
Exercise 5 — Versioning without breaking
- Enable
URLPathVersioning(or manual/api/v1/routes) and duplicate one endpoint with a breaking change (e.g. v2 returnsstarts_atISO with a zone and v1 naive). - Document the deprecation: a
Deprecation: trueheader on v1 once there is usage, and write the metrics query that would measure client migration v1→v2 (what it would count: per endpoint and per day).
Submit
Paste code and curl outputs. Next: Lesson 15 — Validation and contracts with OpenAPI.