⚠️ धडा 07 — Errors आणि idempotency: नम्र नकार आणि पावती क्रमांक
📍 तुम्ही इथे आहात: 12 पैकी धडा 07 — भाग 2 सुरू! · मागे: lesson-06-auth · पुढे: lesson-08-pagination-filtering
📦 या ब्रँचमध्ये काय आहे
धडे 01–06, आणि त्यासोबत लोक विश्वास ठेवतात असा counter आणि लोक शिव्या देतात असा counter
यांना वेगळ्या करणाऱ्या दोन सवयी: नेहमी एकच error आकार, आणि
POST retry करणे सुरक्षित करणारा पावती क्रमांक (Idempotency-Key).
🧒 5 वर्षांच्या मुलाला समजावल्यासारखे
Clerk slip नाकारतो तेव्हा नकार नेहमी त्याच पद्धतीने
लिहिलेला असतो: app वाचू शकेल असा code (validation_failed), माणूस
वाचू शकेल असा message ("The form has problems."), असेल तेव्हा एक hint,
आणि forms साठी, field-वार चुकांची यादी. प्रत्येक नकार,
तीच रचना — म्हणून प्रत्येक app प्रत्येक नकार त्याच code ने हाताळू शकते.
आता retry ची समस्या. तुम्ही "Zoya चे नाव नोंदवा" देता आणि शिक्का परत येण्याआधीच
line तुटते. ते नोंदले गेले का? पुन्हा दिले तर
कदाचित दोन Zoya नोंदल्या जातील. म्हणून counter slip वर एक पावती क्रमांक
स्वीकारतो — Idempotency-Key: enrol-zoya-1. त्या क्रमांकाची slip
आधीच हाताळली गेली असेल तर clerk तेच शिक्का मारलेले
उत्तर परत देतो आणि काहीही नवीन नोंदवत नाही (Idempotent-Replay: true). आता retry करणे
नेहमी सुरक्षित आहे.
आणि सभ्य client पाळतो ते retry चे ढोबळ नियम:
- 4xx — तुमची slip चुकीची आहे; तीच slip पुन्हा देणे निरर्थक आहे.
- 429 / 5xx / timeout — office व्यस्त आहे किंवा बिघडले आहे; backoff आणि jitter
सह retry करा (धडा 10), आणि
POSTसाठी, फक्त पावती क्रमांकासह.
🗺️ आकृती
sequenceDiagram
participant C as 🧑 client
participant S as 🏢 school-api
C->>S: 1 POST /v1/students Idempotency-Key: enrol-zoya-1 {"name":"Zoya",…}
S-->>C: 2 201 Created · Location: /v1/students/6 (reply lost on the network ✂️)
C->>S: 3 POST … Idempotency-Key: enrol-zoya-1 (retry)
S-->>C: 4 201 Created · Idempotent-Replay: true · the SAME body, nothing new filed
C->>S: 5 POST … {"name":"","class":"9Z"}
S-->>C: 6 400 {"error":{"code":"validation_failed","message":…,"problems":[…]}}
Note over C,S: 4xx = fix the slip · 429/5xx/timeout = retry with backoff (+ a receipt number for POST)
❓ काय
- Error आकार:
{"error": {"code", "message", "hint"?, "problems"?}}.codeही स्थिर, machine ला वाचता येणारी string आहे (contract चा भाग);messageबदलू शकतो. काही teams प्रमाणित "problem details" format (RFC 9457) वापरतात — प्रमाणित field नावांसह तीच कल्पना. - Status विरुद्ध code: status कुटुंब निवडतो (
400), code नेमकी केस निवडतो (validation_failed,bad_sort,invalid_json). - Idempotency-Key: प्रत्येक हेतूसाठी client ने तयार केलेली एकमेव string
(प्रत्येक "Zoya चे नाव नोंदवा" साठी एक, प्रत्येक प्रयत्नासाठी नाही). Server काही काळ
key → responseसाठवतो आणि ते पुन्हा देतो. तीच key पण वेगळ्या body सह म्हणजे कडक APIs मध्ये conflict (422/409). - 4xx कधीच retry करू नका (
429सोडून, ज्याचा अर्थ "आत्ता नाही"). Retry करा502/503/504, connection errors आणि timeouts — ते office चे प्रश्न आहेत, slip चे नाहीत. 5xxमध्ये stack traces कधीच बाहेर जाऊ नयेत; ते request id सह log करा (धडा 12) आणि तोच error आकार परत द्या.
🤔 का
कारण clients तुमच्या यशांइतकेच तुमच्या errors च्या आधारावर लिहिले जातात:
checkout page ला कळायला हवे की "तुमचा card नंबर दुरुस्त करा" म्हणायचे
की "एका मिनिटाने पुन्हा प्रयत्न करा". एकच आकार आणि प्रामाणिक status codes
यामुळे ते तीन ओळींचे switch बनते; मनमानी errors मुळे तो अंदाजांचा खेळ बनतो.
आणि पावती क्रमांकांमुळेच payment APIs दोनदा पैसे कापणे टाळतात — ही
पद्धत REST पेक्षा जुनी आहे आणि त्याच्यानंतरही टिकेल.
🔧 कसे (या repo मध्ये)
school_api.py मधले error() हे एकमेव नकार लिहिणारे आहे. do_POST मध्ये,
IDEMPOTENCY[key] = (201, student) उत्तर लक्षात ठेवते; सुरुवातीची replay
शाखा body वाचण्याच्याही आधी ते Idempotent-Replay: true सह
परत देते.
🧪 करून पाहा
K='X-API-Key: hall-pass-123'; B=http://127.0.0.1:8080/v1; J='Content-Type: application/json'
curl -si -X POST $B/students -H "$K" -H "$J" -H 'Idempotency-Key: enrol-zoya-1' -d '{"name":"Zoya","class":"3B"}' | sed -n '1p;/Location/p;$p'
curl -si -X POST $B/students -H "$K" -H "$J" -H 'Idempotency-Key: enrol-zoya-1' -d '{"name":"Zoya","class":"3B"}' | sed -n '1p;/Idempotent-Replay/p;$p'
curl -s "$B/students?limit=20" | grep -o '"name": "Zoya"' | wc -l # 1, not 2
curl -s "$B/students?sort=age" # 400 bad_sort — same shape
✅ तपासा — तुम्हाला काय दिसायला हवे
त्याच id सह दोन एकसारखे 201; दुसऱ्यावर Idempotent-Replay: true असते; यादीत एकच Zoya असते. sort=age च्या नकाराचा आकार smoke test मधल्या इतर प्रत्येक नकारासारखाच {"error": {...}} असतो.
🏁 तुम्ही आत्ताच काय सिद्ध केले
हरवलेले उत्तर आता धोकादायक नाही: पावती क्रमांकासह, retry केलेला POST एकदाच नोंद करतो. आणि तुमचे API करत असलेला प्रत्येक नकार client code च्या एकाच तुकड्याने हाताळता येतो.
⚠️ नेहमीच्या चुका
- प्रत्येक endpoint साठी वेगळा error format (
{"msg"},{"errors": [...]}, साधा text) — clients ते हाताळणे सोडून देतात {"success": false}सह200— प्रत्येक monitoring साधनाला अदृश्य (धडा 02)- पावती क्रमांकाशिवाय
POST"फक्त एकदा" retry करणे — हाच तो दुहेरी-order bug - प्रत्येक प्रयत्नासाठी नवीन
Idempotency-Key— key हेतूची असायला हवी 5xxbodies मध्ये stack traces उघड करणे
🏭 प्रत्यक्ष वापरात हे का महत्त्वाचे: Stripe, Adyen आणि प्रत्येक गंभीर payment API
POSTवर idempotency key मागते, आणि कोणत्याही API forum वरची सर्वात मोठी तक्रार म्हणजे विसंगत errors. गरज पडण्याआधीच या दोन्ही सवयी उचला.
⏭️ पुढे
"पुढचे 20, कृपया" — कोणालाही न गमावता pagination, filtering आणि sorting.
git checkout lesson-08-pagination-filtering