- सॉफ्टवेयर इंजीनियरिंग में API एक मुख्य टूल है, और अच्छे API की वांछनीय विशेषता यह है कि वह इतना परिचित और सरल हो कि लगभग उबाऊ लगे
- API एक बार सार्वजनिक हो जाए तो उसे बदलना मुश्किल होता है, इसलिए यूज़र environment को न तोड़ने का सिद्धांत (WE DO NOT BREAK USERSPACE) महत्वपूर्ण है
- यदि बदलाव अपरिहार्य हो, तो versioning की ज़रूरत पड़ती है, लेकिन यह जटिलता और maintenance cost को बहुत बढ़ाने वाली एक ज़रूरी बुराई है
- API की गुणवत्ता अंततः प्रोडक्ट के अपने मूल्य पर निर्भर करती है, और खराब ढंग से डिज़ाइन किए गए प्रोडक्ट के लिए अच्छा API बनाना कठिन होता है
- स्थिरता और विस्तारयोग्यता के लिए API key आधारित authentication, idempotency, rate limit, cursor-based pagination आदि पर विचार करना चाहिए
प्रस्तावना: API डिज़ाइन का महत्व और संदर्भ
- आधुनिक सॉफ्टवेयर इंजीनियर के प्रमुख कामों में से एक API के साथ इंटरैक्ट करना है
- लेखक के पास भी REST, GraphQL, command-line tools आदि जैसे विभिन्न रूपों में public और internal API को डिज़ाइन/इम्प्लीमेंट/उपयोग करने का अनुभव है
- मौजूदा API डिज़ाइन सलाह अक्सर जटिल अवधारणाओं (REST की परिभाषा, HATEOAS आदि) पर अत्यधिक केंद्रित रहती है
- यह लेख वास्तविक अनुभव के आधार पर व्यावहारिक API डिज़ाइन सिद्धांतों को व्यवस्थित करता है
परिचितपन और लचीलापन का संतुलन: अच्छे API की पहली शर्त
- अच्छा API एक 'साधारण और उबाऊ' API होता है, यानी उसका इस्तेमाल पहले देखे गए API जैसा महसूस होना चाहिए
- यूज़र API से ज़्यादा अपने लक्ष्य को पूरा करने पर ध्यान देता है, इसलिए low barrier वाली डिज़ाइन ज़रूरी है
- एक बार public हो जाने के बाद API को बदलना बहुत मुश्किल हो जाता है, इसलिए शुरुआती डिज़ाइन चरण में सावधानी चाहिए
- डेवलपर जहाँ संभव हो API को सरल रखना चाहते हैं, वहीं लंबी अवधि की flexibility बचाए रखने की चिंता भी बनी रहती है
- नतीजतन, परिचितपन और दीर्घकालिक flexibility के बीच संतुलन ही मुख्य चुनौती है
यूज़रस्पेस को कभी न तोड़ें (WE DO NOT BREAK USERSPACE)
- मौजूदा response structure में fields जोड़ना ज़्यादातर मामलों में समस्या नहीं बनता
- लेकिन field हटाना, type या structure बदलना सभी consumer code को तोड़ सकता है
- API maintainers की यह ज़िम्मेदारी है कि वे मौजूदा यूज़र्स के software को जानबूझकर न तोड़ें
- HTTP के
referer header की वर्तनी गलती तक न सुधारे जाने की वजह भी यूज़रस्पेस को बचाए रखने की संस्कृति है
API को तोड़े बिना बदलना: versioning रणनीति
- केवल अनिवार्य होने पर ही API में breaking changes की अनुमति देनी चाहिए, और ऐसे में versioning ही सही रास्ता है
- पुराने और नए version को एक साथ चलाते हुए gradual migration के लिए प्रेरित करना चाहिए
- version identifier को URL(
/v1/), header आदि कई तरीकों से इस्तेमाल किया जा सकता है, और यूज़र अपनी गति से migrate कर सकते हैं
- versioning के साथ बहुत बड़ा maintenance cost (endpoint बढ़ना, testing, support) और यूज़र confusion जैसी कमियाँ आती हैं
- Stripe की तरह अंदरूनी translation layer रखी जाए तब भी मूल जटिलता से बचा नहीं जा सकता
- API versioning अपनाना आख़िरी उपाय होना चाहिए
API की सफलता पूरी तरह प्रोडक्ट के मूल्य पर निर्भर करती है
- API मूलतः वास्तविक business product का सिर्फ interface है
- OpenAI, Twilio जैसी API में भी आखिरकार यूज़र को चाहिए वह functionality जो API उपलब्ध कराती है
- यदि प्रोडक्ट मूल्यवान है, तो API असुविधाजनक होने पर भी लोग उसका उपयोग करेंगे
- API quality एक तरह की margin विशेषता है: यह तब चयन का कारक बनती है जब मूल प्रतिस्पर्धात्मक क्षमता लगभग समान हो
- इसके विपरीत, बिल्कुल API न होना तकनीकी यूज़र्स के लिए बड़ा अवरोध है
अगर प्रोडक्ट डिज़ाइन खराब है, तो API भी अच्छा नहीं बन सकता
- तकनीकी रूप से परिष्कृत API होने पर भी यदि प्रोडक्ट की market viability नहीं है, तो उसका अर्थ सीमित रह जाता है
- इससे भी महत्वपूर्ण बात यह है कि यदि बुनियादी resource structure अलॉजिकल या अक्षम है, तो वह API में भी दिखेगा
- उदाहरण के लिए, comments को linked list में स्टोर करने वाली system में RESTful डिज़ाइन भी स्वाभाविक रूप से निकालना कठिन हो जाता है
- UI में जो तकनीकी समस्याएँ छिप सकती हैं, वे API में खुलकर सामने आ जाती हैं और यूज़र पर सिस्टम की अनावश्यक समझ थोपती हैं
authentication और यूज़र्स की विविधता
- long-lived API key आधारित authentication को अनिवार्य रूप से support करना चाहिए
- OAuth जैसी अधिक secure विधि का अतिरिक्त support दिया जाए तब भी, API key का entry barrier बहुत कम होता है
- API consumer सिर्फ इंजीनियर नहीं होते; कई non-developer भी होते हैं (sales, planning, students, hobby developers आदि)
- कठिन या जटिल authentication आवश्यकताएँ (जैसे OAuth) गैर-विशेषज्ञ यूज़र्स के लिए बाधा बनती हैं
idempotency और retry handling
- action-oriented requests (जैसे payment, state change आदि) में failure होने पर retry की सुरक्षा बहुत महत्वपूर्ण है
- idempotency का अर्थ है यह सुनिश्चित करना कि एक ही request कई बार भेजी जाए तब भी परिणाम सिर्फ एक बार ही प्रोसेस हो
- मानक तरीका यह है कि duplicate processing रोकने के लिए idempotency key को parameter या header के रूप में भेजा जाए
- idempotency key को स्टोर करने के लिए Redis जैसे सरल key/value store पर्याप्त हैं, और अधिकांश मामलों में periodic expiry भी ठीक रहती है
- read/delete requests (REST शैली) में आमतौर पर इसकी ज़रूरत नहीं होती
API सुरक्षा और rate limiting
- कोड के जरिए API requests, यूज़र के मैनुअल ऑपरेशन की तुलना में कहीं तेज़ी से हो सकती हैं
- अनजाने में deploy की गई एक API भी किसी अप्रत्याशित उपयोग (जैसे बड़े पैमाने के chat system) में लग सकती है
- rate limit अनिवार्य है, और महँगे operations पर इसे और सख़्ती से लागू किया जाना चाहिए
- किसी विशेष ग्राहक के लिए अस्थायी API disablement (killswitch) को भी एक विकल्प के रूप में सोचना चाहिए
- response headers (
X-Limit-Remaining, Retry-After आदि) के जरिए rate limit जानकारी देनी चाहिए
pagination रणनीति
- बड़े dataset (जैसे लाखों tickets) को कुशलता से लौटाने के लिए pagination अनिवार्य है
- offset-based pagination सरल है, लेकिन बड़े data पर धीरे-धीरे धीमी हो जाती है
- cursor-based pagination query performance घटाए बिना बहुत बड़े dataset पर भी प्रभावी रहती है
- cursor-based तरीका implementation और उपयोग दोनों में थोड़ा कठिन है, लेकिन लंबी अवधि में यह अनिवार्य बदलाव साबित हो सकता है
- response में
next_page field आदि शामिल करके अगले request के cursor को स्पष्ट रूप से बताना समझदारी है
optional fields और GraphQL पर दृष्टिकोण
- महँगे या धीमे fields को default response से बाहर रखना चाहिए और ज़रूरत होने पर ही selectively जोड़ना चाहिए
includes parameter आदि से related data शामिल किया जा सकता है
- GraphQL में data structure flexibility का लाभ है, लेकिन non-developer accessibility में कमी, caching/edge case की जटिलता, backend implementation की कठिनाई जैसी समस्याएँ भी हैं
- व्यावहारिक अनुभव के आधार पर, GraphQL को सिर्फ तभी अपनाना उचित है जब इसकी वास्तव में आवश्यकता हो
internal API की विशेषताएँ
- internal API की परिस्थितियाँ external API (public API) से कई मायनों में अलग होती हैं
- इनके consumer अधिकांशतः पेशेवर software engineers होते हैं, इसलिए अधिक जटिल authentication या breaking changes संभव हो सकते हैं
- फिर भी, idempotency, दुर्घटना-निवारण और operational burden को कम करने वाले डिज़ाइन सिद्धांत यहाँ भी लागू होते हैं
सारांश
- API को बदलना कठिन और उपयोग करना आसान होना चाहिए
- यूज़रस्पेस को न तोड़ना API maintainers का सबसे महत्वपूर्ण कर्तव्य है
- API versioning की लागत बहुत अधिक है, इसलिए इसका उपयोग केवल आख़िरी उपाय के रूप में होना चाहिए
- अंततः API की गुणवत्ता प्रोडक्ट के मूल मूल्य से तय होती है
- खराब ढंग से डिज़ाइन किए गए प्रोडक्ट की सीमाएँ API स्तर पर सुधार करके भी पूरी तरह दूर नहीं की जा सकतीं
- सरल authentication का support, ज़रूरी action requests में idempotency, और rate limiting/pagination जैसे stability उपाय महत्वपूर्ण हैं
- internal API के लिए उपयोग और लक्षित यूज़र के अनुसार रणनीति अलग हो सकती है, लेकिन सावधानीपूर्वक डिज़ाइन की आवश्यकता बनी रहती है
- REST, JSON जैसे format या OpenAPI आदि मूल मुद्दे नहीं हैं; स्पष्ट documentation अधिक महत्वपूर्ण है
अभी कोई टिप्पणी नहीं है.