Idempotency
A member taps "Pay fine" on a train. The request reaches BookNook and the payment goes through, but the tunnel swallows the response. The app sees a timeout and retries. Did the member just pay twice? Idempotency is what lets a client retry without fear.
The rule
Same request twice, same result as once.
An operation is idempotent if repeating it leaves the server in the same state as doing it once. The response may differ, but the effect does not.
GET /v1/books/42: reading changes nothing. Idempotent (and safe).PUT /v1/books/42with a full book: the second replace writes the same thing. Idempotent.DELETE /v1/loans/901: after the first call the loan is gone; the second may return404, but the state is the same. Idempotent.POST /v1/payments: each call creates a new payment. Not idempotent.PATCHdepends on the change: "set shelf to C2" is idempotent; "add 1 to the renewal count" is not.
For operations that are not naturally idempotent, the client sends an idempotency key: a unique value it generates once per intended action and reuses on every retry of that action.
POST /v1/payments HTTP/1.1
Idempotency-Key: 5f2b8e0c-6a3d-4c1e-9b7a-2d4e8f1a0c93
Content-Type: application/json
{"fine_id": 312, "amount": 150}The server records the key with the result of the first successful attempt. When the same key arrives again, it does not charge again; it returns the stored response. Keys expire after a window, say 24 hours. If the same key comes back with a different body, that is a client bug, and the server should refuse it rather than guess, often with 422 or 409.
The shortcut
For each endpoint, imagine the network drops the response and the client retries. Does the second call change anything the first did not? If yes, it needs an idempotency key, or a redesign.
Picture the retry
The first renewal worked, but the response was lost. The app sends it again.
The trap is generating a fresh key on every retry. Then each attempt looks new and the protection vanishes. The key belongs to the action, not to the HTTP attempt.
Drills
Answer fast — trust the rule.
Which request is naturally idempotent?
The second DELETE /v1/loans/901 returns 404, while the first returned 204. Is DELETE still idempotent?
A payment retry carries the same Idempotency-Key as a request that already succeeded. What should the server do?
When should the app create a NEW idempotency key?
Remember
- Same request twice, same result as once.
- Shortcut: imagine the lost response and the retry; does the second call change anything?
- Trap: a new key per retry, and POST endpoints that move money with no key at all.
