Go API त्रुटि हैंडलिंग पैटर्न जो टाइप्ड एरर, HTTP स्टेटस मैपिंग, request IDs और सुरक्षित संदेशों को मानकीकृत करके इंटरनल्स लीक होने से रोकते हैं।

जब हर एंडपॉइंट विफलताओं की रिपोर्ट अलग तरीके से करता है, तो क्लाइंट्स आपकी API पर भरोसा करना बंद कर देते हैं। एक रूट लौटाता है { "error": "not found" }, दूसरा { "message": "missing" } लौटाता है, और तीसरा साधारण टेक्स्ट भेज देता है। अर्थ करीब भी हो सकता है, लेकिन क्लाइंट को अब अंदाज़ा लगाना पड़ता है कि क्या हुआ।
लागत जल्दी दिखती है। टीमें नाज़ुक पार्सिंग लॉजिक बनाती हैं और हर एंडपॉइंट के लिए स्पेशल केस जोड़ती हैं। रिट्राइज रिस्की हो जाते हैं क्योंकि क्लाइंट यह नहीं बता सकता कि "फिर से कोशिश करें" या "आपका इनपुट गलत है"। सपोर्ट टिकट बढ़ते हैं क्योंकि क्लाइंट केवल एक अस्पष्ट संदेश देखता है, और आपकी टीम आसानी से इसे सर्वर-लॉग लाइन से मैच नहीं कर पाती।
एक साधारण परिदृश्य: एक मोबाइल ऐप साइनअप के दौरान तीन एंडपॉइंट्स को कॉल करता है। पहला HTTP 400 लौटाता है फ़ील्ड-स्तर त्रुटि मैप के साथ, दूसरा HTTP 500 के साथ एक स्टैक ट्रेस स्टリング लौटाता है, और तीसरा HTTP 200 के साथ { "ok": false } लौटाता है। ऐप टीम तीन अलग त्रुटि हैंडलर शिप करती है, और बैकएंड टीम को अभी भी रिपोर्ट मिलती है जैसे "signup कभी-कभी फेल होता है" बिना किसी सुराग के।
लक्ष्य एक पूर्वानुमेय कॉन्ट्रैक्ट है। क्लाइंट्स को भरोसेमंद तरीके से पढ़ना चाहिए कि क्या हुआ—क्या उनकी गलती थी या आपकी, क्या retry समझदारी है, और एक request ID जिसे वे सपोर्ट में पेस्ट कर सकें।
स्कोप नोट: यह JSON HTTP APIs (gRPC नहीं) पर केंद्रित है, लेकिन वही विचार किसी भी जगह लागू होते हैं जहाँ आप अन्य सिस्टम्स को त्रुटियाँ लौटाते हैं।
एक स्पष्ट कॉन्ट्रैक्ट चुनें और हर एंडपॉइंट को उसका पालन कराएँ। “सुसंगत” का मतलब है वही JSON आकार, फ़ील्ड्स का वही अर्थ, और वही व्यवहार चाहे कौन-सा हैंडलर फेल हुआ हो। एक बार ऐसा होने पर, क्लाइंट्स अनुमान लगाना बंद कर देंगे और त्रुटियों को हैंडल करने लगेंगे।
एक उपयोगी कॉन्ट्रैक्ट क्लाइंट्स को बताता है कि आगे क्या करना है। अधिकांश ऐप्स के लिए, हर त्रुटि उत्तर को तीन प्रश्नों का उत्तर देना चाहिए:
व्यावहारिक नियमों का सेट:
पहले से तय कर लें कि क्या वस्तुएँ कभी response में नहीं दिखनी चाहिए। सामान्य “कभी नहीं” आइटम में SQL फ्रैगमेंट, स्टैक ट्रेस, आंतरिक होस्टनेम, सीक्रेट्स, और डिपेंडेंसी से मिलने वाले कच्चे एरर स्ट्रिंग्स शामिल हैं।
एक साफ़ विभाजन रखें: एक छोटा यूज़र-फेसिंग संदेश (सुरक्षित, विनम्र, कार्रवाईयोग्य) और आंतरिक विवरण (पूर्ण त्रुटि, स्टैक, और संदर्भ) लॉग्स में रखें। उदाहरण के लिए, “Could not save your changes. Please try again.” सुरक्षित है। “pq: duplicate key value violates unique constraint users_email_key” सुरक्षित नहीं है।
जब हर एंडपॉइंट एक ही कॉन्ट्रैक्ट फॉलो करे, तो क्लाइंट एक ही त्रुटि हैंडलर बना सकता है और उसे हर जगह पुन: उपयोग कर सकता है।
क्लाइंट्स तभी त्रुटियों को साफ़-सुथरे ढंग से हैंडल कर सकते हैं जब हर एंडपॉइंट एक ही आकार में जवाब दे। एक JSON एंवेलप चुनें और उसे स्थिर रखें।
एक व्यावहारिक डिफ़ॉल्ट है एक error ऑब्जेक्ट प्लस शीर्ष-स्तर request_id:
{
"error": {
"code": "VALIDATION_FAILED",
"message": "Some fields are invalid.",
"details": {
"fields": {
"email": "must be a valid email address"
}
}
},
"request_id": "req_01HV..."
}
HTTP स्टेटस व्यापक श्रेणी देता है (400, 401, 409, 500)। मशीन-रीडेबल error.code क्लाइंट के लिए विशिष्ट केस देता है जिस पर वह ब्रांच कर सके। यह विभाजन इसलिए महत्वपूर्ण है क्योंकि कई अलग समस्याएँ एक ही स्टेटस शेयर कर सकती हैं। एक मोबाइल ऐप EMAIL_TAKEN और WEAK_PASSWORD के लिए अलग UI दिखाना चाहेगा, भले ही दोनों 400 हों।
error.message को सुरक्षित और मानव-सुमुखी रखें। यह उपयोगकर्ता को समस्या सुधारने में मदद करना चाहिए, पर इंटरनल्स कभी लीक न करें (SQL, स्टैक ट्रेसेस, प्रोवाइडर नाम, फ़ाइल पथ)।
वैकल्पिक फ़ील्ड्स उपयोगी होते हैं जब वे पूर्वानुमेय बने रहें:
details.fields एक मैप के रूप में फ़ील्ड से संदेश।details.retry_after_seconds।details.docs_hint सादा टेक्स्ट के रूप में (URL नहीं)।बैकवर्ड कम्पैटिबिलिटी के लिए, error.code मानों को अपनी API कॉन्ट्रैक्ट का हिस्सा समझें। नए कोड जोड़ें बिना पुराने अर्थ बदले। केवल वैकल्पिक फ़ील्ड जोड़ें, और मान लें कि क्लाइंट अज्ञात फ़ील्ड्स को इग्नोर कर देगा।
जब हर हैंडलर अपनी विफलता संकेत करने का अपना तरीका बनाता है तो एरर हैंडलिंग जटिल हो जाती है। कुछ टाइप्ड एरर से यह सुधार जाता है: हैंडलर्स ज्ञात एरर टाइप लौटाएँ, और एक रेस्पॉन्स लेयर उन्हें सुसंगत उत्तरों में बदल दे।
एक व्यावहारिक स्टार्टर सेट अधिकांश एंडपॉइंट्स को कवर कर देता है:
कुंजी यह है कि शीर्ष स्तर पर स्थिरता रहे, भले ही मूल कारण बदले। आप लोअर-लेवल एरर्स (SQL, नेटवर्क, JSON पार्सिंग) को रैप कर सकते हैं पर वही सार्वजनिक प्रकार लौटाएँ जिसे मिडलवेयर पहचान सके।
type NotFoundError struct {
Resource string
ID string
Err error // private cause
}
func (e NotFoundError) Error() string { return "not found" }
func (e NotFoundError) Unwrap() error { return e.Err }
अपने हैंडलर में, सीधे sql.ErrNoRows लीक करने की बजाय NotFoundError{Resource: "user", ID: id, Err: err} लौटाएँ।
एरर्स चेक करने के लिए, कस्टम टाइप्स के लिए errors.As और सेंटिनल एरर्स के लिए errors.Is पसंद करें। सेंटिनल एरर्स (जैसे var ErrUnauthorized = errors.New("unauthorized")) साधारण मामलों के लिए काम करते हैं, पर जब आपको सुरक्षित संदर्भ (जैसे कौन-सा रिसोर्स गायब था) चाहिए तो कस्टम टाइप्स बेहतर हैं बिना आपकी सार्वजनिक प्रतिक्रिया कॉन्ट्रैक्ट बदले।
जो चीज़ें आप जोड़ते हैं उन पर सख्ती बरतें:
Err, स्टैक जानकारी, कच्चे SQL एरर्स, टोकन, उपयोगकर्ता डेटा।यह विभाजन आपको क्लाइंट्स की मदद करने देता है बिना इंटरनल्स उजागर किए।
एक बार जब आपके पास टाइप्ड एरर हों, अगला काम उबाऊ पर आवश्यक है: वही एरर प्रकार हमेशा वही HTTP स्टेटस पैदा करे। क्लाइंट्स उसी के आधार पर लॉजिक बनाएंगे।
एक व्यावहारिक मैपिंग जो अधिकांश APIs पर काम करती है:
| Error type (example) | Status | When to use it |
|---|---|---|
| BadRequest (malformed JSON, missing required query param) | 400 | The request is not valid at a basic protocol or format level. |
| Unauthenticated (no/invalid token) | 401 | The client needs to authenticate. |
| Forbidden (no permission) | 403 | Auth is valid, but access is not allowed. |
| NotFound (resource ID does not exist) | 404 | The requested resource is not there (or you choose to hide existence). |
| Conflict (unique constraint, version mismatch) | 409 | The request is well-formed, but it clashes with current state. |
| ValidationFailed (field rules) | 422 | The shape is fine, but business validation fails (email format, min length). |
| RateLimited | 429 | Too many requests in a time window. |
| Internal (unknown error) | 500 | Bug or unexpected failure. |
| Unavailable (dependency down, timeout, maintenance) | 503 | Temporary server-side issue. |
दो विभेद जो बहुत भ्रम रोकते हैं:
Retry मार्गदर्शन मायने रखता है:
एक request ID एक छोटा यूनिक वैल्यू है जो एक API कॉल को end-to-end पहचानता है। अगर क्लाइंट हर उत्तर में इसे देख सके, तो सपोर्ट आसान हो जाता है: “मुझे request ID भेजें” अक्सर सही लॉग और फेलियर खोजने के लिए काफी होता है।
यह आदत सफलता और त्रुटि दोनों उत्तरों के लिए उपयोगी है।
एक स्पष्ट नियम अपनाएँ: अगर क्लाइंट request ID भेजता है, तो उसे रखें। अगर नहीं भेजता, तो नया बनाइए।
X-Request-Id).request ID को तीन जगह रखें:
request_id के रूप में)बैच एंडपॉइंट्स या बैकग्राउंड जॉब्स के लिए एक parent request ID रखें। उदाहरण: क्लाइंट 200 पंक्तियाँ अपलोड करता है, 12 वैलिडेशन में फेल होती हैं, और आप वर्क enqueue करते हैं। पूरे कॉल के लिए एक request_id लौटाएँ, और प्रत्येक जॉब व प्रत्येक प्रति-आइटम त्रुटि पर parent_request_id शामिल करें। इस तरह आप "एक अपलोड" को ट्रेस कर सकते हैं भले ही वह बहुत से टास्क में फैल जाए।
क्लाइंट्स को एक साफ, स्थिर त्रुटि उत्तर चाहिए। आपके लॉग्स को गंदी सच्चाई चाहिए। उन दोनों दुनियाओं को अलग रखें: क्लाइंट को सुरक्षित संदेश और सार्वजनिक एरर कोड दें, जबकि इंटरनल कारण, स्टैक और संदर्भ सर्वर पर लॉग करें।
हर त्रुटि उत्तर के लिए एक संरचित ईवेंट लॉग करें, जिसे request_id से खोजा जा सके।
रखने योग्य फ़ील्ड्स:
आंतरिक विवरण केवल सर्वर लॉग्स (या आंतरिक त्रुटि स्टोर) में रखें। क्लाइंट कभी भी कच्चे डेटाबेस एरर्स, क्वेरी टेक्स्ट, स्टैक ट्रेसेस, या प्रोवाइडर संदेश नहीं देखना चाहिए। यदि आप कई सर्विसेस चलाते हैं, तो एक आंतरिक फ़ील्ड जैसे source (api, db, auth, upstream) त्रैज में तेज़ी ला सकता है।
शोर वाले एंडपॉइंट्स और rate-limited एरर्स पर नज़र रखें। अगर एक एंडपॉइंट हजारों बार प्रति मिनट समान 429 या 400 पैदा कर सकता है, तो लॉग स्पैम से बचें: रिपीटेड ईवेंट्स को सैंपल करें, या अपेक्षित एरर्स केSeverity को घटाएँ जबकि आप उन्हें मेट्रिक्स में गिनते रहें।
मेट्रिक्स समस्याओं को लॉग से पहले पकड़ लेते हैं। HTTP स्टेटस और एरर कोड द्वारा समूहित काउंट ट्रैक करें, और अचानक spikes पर अलर्ट बनाएं। अगर RATE_LIMITED deploy के बाद 10x बढ़ता है, तो आप इसे जल्दी देख लेंगे भले ही लॉग सैंपलिंग हो।
सबसे आसान तरीका है कि आप हर जगह एरर हैंडलिंग रोक दें और उन्हें एक छोटे पाइपलाइन से गुज़ारें। वह पाइपलाइन तय करती है कि क्लाइंट को क्या दिखे और आप लॉग में क्या रखें।
एक छोटे एरर कोड सेट से शुरू करें जिन पर क्लाइंट भरोसा कर सके (उदाहरण: INVALID_ARGUMENT, NOT_FOUND, UNAUTHORIZED, CONFLICT, INTERNAL)। इन्हें एक टाइप्ड एरर में रैप करें जो केवल सुरक्षित, सार्वजनिक फ़ील्ड्स (code, safe message, वैकल्पिक details जैसे कौन-सा फ़ील्ड गलत है) एक्सपोज़ करे। आंतरिक कारण private रखें।
फिर एक ट्रांसलेटर फ़ंक्शन लागू करें जो किसी भी एरर को (statusCode, responseBody) में बदल दे। यह वही जगह है जहाँ टाइप्ड एरर HTTP स्टेटस को मैप करेंगे, और अज्ञात एरर्स एक सुरक्षित 500 रेस्पॉन्स बन जाएँगे।
अगला, मिडलवेयर जोड़ें जो कि:
request_id होएक panic कभी क्लाइंट को स्टैक ट्रेस नहीं दिखानी चाहिए। सामान्य 500 रेस्पॉन्स लौटाएँ एक सामान्य संदेश के साथ, और उसी request_id के साथ पूर्ण panic लॉग करें।
अंत में, अपने हैंडलर्स को इस तरह बदलें कि वे सीधे response लिखने के बजाय error रिटर्न करें। एक wrapper हैंडलर इसे कॉल कर सकता है, ट्रांसलेटर चलाकर और मानक फ़ॉर्मेट में JSON लिखकर।
एक सम्मानित चेकलिस्ट:
Golden tests इसलिए महत्वपूर्ण हैं क्योंकि वे कॉन्ट्रैक्ट को लॉक कर देते हैं। अगर कोई बाद में संदेश या स्टेटस बदलता है, तो टेस्ट क्लाइंट्स को चौंकाने से पहले फेल कर देंगे।
कल्पना कीजिए एक एंडपॉइंट: क्लाइंट एप एक कस्टमर रिकॉर्ड बनाता है।
POST /v1/customers JSON जैसे { "email": "[email protected]", "name": "Pat" } के साथ। सर्वर हमेशा वही त्रुटि आकार लौटाता है और हमेशा request_id शामिल होता है।
ईमेल गायब है या गलत फ़ॉर्मैट में है। क्लाइंट फ़ील्ड को हाईलाइट कर सके।
{
"request_id": "req_01HV9N2K6Q7A3W1J9K8B",
"error": {
"code": "VALIDATION_FAILED",
"message": "Some fields need attention.",
"details": {
"fields": {
"email": "must be a valid email address"
}
}
}
}
ईमेल पहले से मौजूद है। क्लाइंट साइन इन या दूसरा ईमेल चुनने का सुझाव दे सकता है।
{
"request_id": "req_01HV9N3C2D0F0M3Q7Z9R",
"error": {
"code": "ALREADY_EXISTS",
"message": "A customer with this email already exists."
}
}
कोई डिपेंडेंसी डाउन है। क्लाइंट बैकऑफ के साथ retry कर सकता है और एक शांत संदेश दिखा सकता है।
{
"request_id": "req_01HV9N3X8P2J7T4N6C1D",
"error": {
"code": "TEMPORARILY_UNAVAILABLE",
"message": "We could not save your request right now. Please try again."
}
}
एक ही कॉन्ट्रैक्ट के साथ, क्लाइंट स्थिर प्रतिक्रिया करता है:
details.fields का उपयोग करके फ़ील्ड्स मार्क करेंrequest_id दिखाएँसपोर्ट के लिए, वही request_id आंतरिक लॉग्स में असली कारण तक पहुंचने का सबसे तेज़ रास्ता है, बिना स्टैक ट्रेसेस या डेटाबेस एरर्स को उजागर किए।
क्लाइंट्स को परेशान करने का तेज़ तरीका है उन्हें अनुमान लगाने पर मजबूर करना। अगर एक एंडपॉइंट { "error": "..." } लौटाए और दूसरा { "message": "..." }, तो हर क्लाइंट स्पेशल केस का ढेर बन जाएगा, और बग हफ्तों तक छिपे रह सकते हैं।
कुछ गलतियाँ बार-बार दिखती हैं:
code के।request_id जोड़ना, ताकि किसी यूज़र रिपोर्ट को सफल कॉल से correlate नहीं कर सकें जो बाद में समस्या पैदा कर सकता है।इंटरनल्स लीक करना सबसे आसान जाल है। एक हैंडलर err.Error() लौटाता है क्योंकि यह सुविधाजनक है, और फिर constraint नाम या तृतीय-पक्ष संदेश प्रोडक्शन रिस्पॉन्स में आ जाता है। क्लाइंट संदेश को सुरक्षित और संक्षिप्त रखें, और विस्तृत कारण लॉग्स में रखें।
केवल टेक्स्ट पर निर्भर रहना भी एक धीमी समस्या है। अगर क्लाइंट को अंग्रेज़ी वाक्यों को पार्स करना पड़े जैसे “email already exists,” तो आप wording बदलते ही लॉजिक तोड़ देंगे। स्थिर एरर कोड आपको संदेश समायोजित करने, अनुवाद करने और व्यवहार सुसंगत रखने की अनुमति देते हैं।
एरर कोड्स को अपनी सार्वजनिक कॉन्ट्रैक्ट मानें। अगर आपको किसी कोड को बदलना ही है, तो नया कोड जोड़ें और कुछ समय के लिए पुराना कोड भी काम करता रहे, भले ही दोनों एक ही HTTP स्टेटस को मैप करें।
अंत में, हर उत्तर—सफल या विफल—में वही request_id शामिल करें। जब उपयोगकर्ता कहे "यह काम कर गया, फिर यह टूट गया," वह एक ID अक्सर guessing में एक घंटा बचाती है।
रिलीज़ से पहले एक त्वरित पास:
error.code, error.message, request_id)।VALIDATION_FAILED, NOT_FOUND, CONFLICT, UNAUTHORIZED)। टेस्ट रखें ताकि हैंडलर्स गलती से अज्ञात कोड्स न लौटाएँ।request_id लौटाएँ और लॉग भी करें, पैनिक्स और टाइमआउट्स सहित।इसके बाद कुछ एंडपॉइंट्स को मैन्युअली स्पॉट-चेक करें। एक वैलिडेशन एरर, एक मिसिंग रिकॉर्ड, और एक अप्रत्याशित विफलता ट्रिगर करें। अगर प्रतिक्रियाएँ एंडपॉइंट्स के बीच अलग दिखती हैं (फ़ील्ड्स बदलते हैं, स्टेटस कोड्स भटकते हैं, संदेश ज़्यादा साझा करते हैं), तो किसी और फीचर जोड़ने से पहले साझा पाइपलाइन को ठीक करें।
एक व्यावहारिक नियम: अगर कोई संदेश हमलावर की मदद करेगा या सामान्य उपयोगकर्ता को भ्रमित करेगा, तो वह लॉग्स में होना चाहिए, रेस्पॉन्स में नहीं।
अपनी पसंद की त्रुटि कॉन्ट्रैक्ट लिखें जिसे हर एंडपॉइंट फॉलो करे, भले ही आपकी API पहले से लाइव हो। एक साझा कॉन्ट्रैक्ट (स्टेटस, स्थिर एरर कोड, सुरक्षित संदेश, और request_id) क्लाइंट्स के लिए त्रुटियों को पूर्वानुमेय बनाने का सबसे तेज़ तरीका है।
फिर धीरे-धीरे माइग्रेट करें। मौजूदा हैंडलर्स रखें, पर उनकी विफलताओं को एक मैपर के माध्यम से रूट करें जो आंतरिक एरर्स को आपकी सार्वजनिक प्रतिक्रिया आकार में बदल दे। यह जोखिमभरे बड़े रिफैक्टर के बिना सुसंगतता सुधारता है और नए एंडपॉइंट्स को नए फ़ॉर्मैट बनाने से रोकता है।
एक छोटा एरर कोड कैटलॉग रखें और इसे API का हिस्सा समझें। जब कोई नया कोड जोड़ना चाहे, तो एक त्वरित समीक्षा करें: क्या यह वाकई नया है, नाम स्पष्ट है, और क्या यह सही HTTP स्टेटस से मैप होता है?
कुछ परीक्षण जोड़ें जो ड्रिफ्ट पकड़ें:
request_id शामिल हो।error.code मौजूद हो और कैटलॉग का हिस्सा हो।error.message सुरक्षित हो और कभी भी आंतरिक विवरण न दिखाए।अगर आप शून्य से Go बैकएंड बना रहे हैं, तो कॉन्ट्रैक्ट जल्दी लॉक कर देना मददगार हो सकता है। उदाहरण के लिए, Koder.ai (koder.ai) में एक planning mode है जहाँ आप upfront ऐसी conventions जैसे त्रुटि स्कीमा और कोड कैटलॉग परिभाषित कर सकते हैं, फिर API बढ़ने के साथ हैंडलर्स को aligned रख सकते हैं।
हर त्रुटि उत्तर के लिए एक ही JSON आकार उपयोग करें, सभी एंडपॉइंट्स पर। एक व्यावहारिक डिफ़ॉल्ट है शीर्ष-स्तर request_id और एक error ऑब्जेक्ट जिसमें code, message, और वैकल्पिक details हों—ताकि क्लाइंट विश्वसनीय रूप से पार्स और प्रतिक्रिया दे सकें।
उपयोगकर्ता सुरक्षित, संक्षिप्त वाक्य के रूप में error.message लौटाएँ और वास्तविक कारण सर्वर लॉग में रखें। कच्चे डेटाबेस त्रुटियाँ, स्टैक ट्रेस, आंतरिक होस्टनाम या अन्य डिपेंडेंसी संदेश कभी न भेजें, भले ही विकास के समय वे सहायक लगें।
HTTP स्टेटस कैटेगरी बताता है, पर मशीन-लॉजिक के लिए एक स्थिर error.code जरूरी है। क्लाइंट्स को error.code (जैसे ALREADY_EXISTS) पर शाखा बनानी चाहिए और स्थिति को व्यापक मार्गदर्शक की तरह लेना चाहिए (जैसे 409 एक state conflict को दर्शाता है)।
जब रिक्वेस्ट विश्वसनीय रूप से पार्स न हो सके (बिगड़ा JSON, गलत प्रकार), तो 400 का उपयोग करें। जब रिक्वेस्ट सही ढंग से पार्स हो लेकिन व्यापार नियमों पर खरा न उतरे (अमान्य ईमेल, पासवर्ड छोटा), तब 422 का उपयोग करें।
409 का उपयोग तब करें जब इनपुट वैध हो पर वर्तमान स्टेट से टकराता हो (ईमेल पहले से मौजूद, वर्शन मिसमैच)। 422 फील्ड-स्तर वैलिडेशन के लिए है जहाँ मान बदलने से समस्या सुलझ जाती है बिना सर्वर स्टेट को बदलने की।
एक छोटी सेट टाइप्ड एरर बनाएं (validation, not found, conflict, unauthorized, internal) और हैंडलर्स इन्हें रिटर्न करें। फिर एक साझा ट्रांसलेटर इन प्रकारों को स्टेटस कोड और मानक JSON उत्तर में मैप करे—इससे प्रतिक्रियाएँ सुसंगत रहती हैं।
हर उत्तर में request_id लौटाएँ, सफल या विफल—और हर सर्वर लॉग लाइन पर इसे लॉग करें। क्लाइंट कोई समस्या रिपोर्ट करे तो वही ID अक्सर सही लॉग एंट्री तक पहुंचने के लिए काफी होता है।
सिर्फ़ { "ok": false } के साथ HTTP 200 लौटाना गलत है। 200 केवल तब लौटाएँ जब ऑपरेशन सफल हो; त्रुटियों के लिए 4xx/5xx उपयोग करें। 200 के पीछे त्रुटियाँ छिपाने से क्लाइंट्स को बॉडी फ़ील्ड्स पार्स करने पर मजबूर होना पड़ता है और व्यवहार असंगत होता है।
सामान्यतः 400, 401, 403, 404, 409 और 422 के लिए बिना बदलाव के retry न करें क्योंकि retry से मदद नहीं मिलेगी। 503 के लिए retry करें, और कभी-कभी 429 के लिए भी (थोड़ी देर बाद); अगर आप idempotency keys सपोर्ट करते हैं तो ट्रांज़िएंट फेलियर पर POST के लिए retries सुरक्षित बनती हैं।
कुछ “गोल्डन” टेस्ट रखें जो सुनिश्चित करें: हर त्रुटि उत्तर में request_id हो; स्टेटस कोड एरर प्रकार से मेल खाता हो; error.code कैटलॉग से हो; error.message सुरक्षित हो; और अज्ञात त्रुटियाँ 500 पर generic संदेश के साथ fallback हों। इससे विकसित होते समय उत्तरों के ड्रिफ्ट होने से बचाव होगा।