# Idempotency Keys — API Design और Versioning

Source: https://www.geekswithgeeks.com/hi/api-design/rel-idempotency

> Client द्वारा दी गई idempotency key से POST अनुरोधों को retry के लिए सुरक्षित बनाएँ।

## दोहरे शुल्क की समस्या

Client `POST /payments` भेजता है, connection टूट जाता है, और उसे पता नहीं कि भुगतान हुआ या नहीं। आँख मूँदकर retry करने से दो बार शुल्क लग सकता है। **Idempotency key** इसे हल करती है: client *इरादे* के लिए अनोखा मान (UUID) बनाता है और `Idempotency-Key` header में भेजता है। Server उस key के नीचे **नतीजा** रखता है; वही key फिर आए तो कार्य दोहराने की जगह रखा नतीजा लौटाता है, आम तौर पर ऐसे header के साथ जो उसे replay बताए। Keys एक अवधि (जैसे 24 घंटे) बाद expire होनी चाहिए, और **अलग** request body के साथ key दोबारा उपयोग करना अस्वीकार होना चाहिए। असली side effects वाले ऑपरेशनों, जैसे भुगतान, orders, emails, के लिए ऐसी keys अनिवार्य करें।

## सुरक्षित retries, सस्ते दोहराव

Networks विफल होते हैं, इसलिए अच्छी तरह डिज़ाइन किए APIs retries को सुरक्षित और बार-बार की reads को सस्ता बनाते हैं।

![चार साधन: idempotency, caching, सीमाएँ, async।](assets/figures/api-design/section-3-map.svg) — चित्र 3.1 — Idempotency, caching, सीमाएँ और async।

## दोहराया गया भुगतान, चलाकर

मैंने यह केवल Python standard library से बने छोटे असली HTTP API पर चलाया (पूरा कोड केस स्टडी में)। पहला `POST` key `abc-123` के साथ `pay_1` बनाता है (`201`, `Location` header के साथ)। वैसा ही retry वही भुगतान `200` और `Idempotent-Replayed: true` के साथ लौटाता है, और `b1 == b2` True है। Key ग़ायब हो तो `400`, और अमान्य amount पर field विवरण के साथ `422` मिलता है।

```python
# uses srv, base and call() from the runnable demo in the case study
k = {"Idempotency-Key": "abc-123", "Content-Type": "application/json"}
s1, h1, b1 = call("POST", "/v1/payments", {"amount": 500}, k); s2, h2, b2 = call("POST", "/v1/payments", {"amount": 500}, k)
print(s1, b1, h1.get("Location")); print(s2, b2, h2.get("Idempotent-Replayed"), b1 == b2)
print(call("POST", "/v1/payments", {"amount": 500}, {"Content-Type": "application/json"})[0], call("POST", "/v1/payments", {"amount": -5}, {**k, "Idempotency-Key": "z"})[2]["errors"])

```

Output:

```
201 {'id': 'pay_1', 'amount': 500, 'status': 'succeeded'} /v1/payments/pay_1
200 {'id': 'pay_1', 'amount': 500, 'status': 'succeeded'} true True
400 [{'field': 'amount', 'message': 'must be > 0'}]
```

## Key और नतीजा अणु-रूप से रखें

दो retries एक ही समय आ सकते हैं। काम से पहले key आरक्षित करें (जैसे database की unique constraint से) ताकि सिर्फ़ एक अनुरोध चले और दूसरा इंतज़ार करे या रखा नतीजा पाए।

**Quiz:** समान अनुरोध के साथ दोहराई Idempotency-Key मिलने पर server क्या करता है?

- [ ] पहला नतीजा हटाता है
- [ ] कार्य फिर करता है
- [x] कार्य दोहराए बिना रखा नतीजा लौटाता है
- [ ] Crash हो जाता है

*Answer:* कार्य दोहराए बिना रखा नतीजा लौटाता है. Key retries को मूल प्रयास से जोड़ती है ताकि side effect एक बार हो।
