OpenAPI किसी HTTP API को एक सामान्य YAML या JSON फ़ाइल में लिखकर रखने का प्रारूप है। उस फ़ाइल में दर्ज होता है कि API कौन-कौन से path खोलता है, हर path कौन-सी method स्वीकार करता है, request में कौन-से field जाते हैं और response में क्या लौटता है। फ़ाइल इंसान भी पढ़ सकता है और प्रोग्राम भी, इसीलिए दस्तावेज़, client library और परीक्षण के लिए बनाए जाने वाले नकली server — तीनों एक ही स्रोत से तैयार हो जाते हैं।
औपचारिक नाम है OpenAPI Specification, संक्षेप में OAS। इसे OpenAPI Initiative सँभालता है, जो Linux Foundation के अंतर्गत खुले प्रशासन वाला प्रोजेक्ट है।
आगे: दस्तावेज़ की बनावट, OpenAPI और Swagger का फ़र्क़, संस्करण 3.1 और 3.2 में क्या बदला, और यह कि इस प्रारूप का सबसे बड़ा वादा — दस्तावेज़ कभी पुराना नहीं पड़ेगा — अपने आप पूरा क्यों नहीं होता।
OpenAPI दस्तावेज़ दिखता कैसा है
चलने लायक फ़ाइल उतनी लंबी नहीं होती जितना लोग मान लेते हैं:
openapi: 3.1.0
info:
title: लिंक
version: "1.0"
paths:
/links:
post:
summary: छोटा लिंक बनाएँ
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [url]
properties:
url:
type: string
format: uri
responses:
'201':
description: लिंक बन गया
सबसे ऊपरी स्तर पर ज़रूरी field सिर्फ़ दो हैं, openapi और info; इनके अलावा दस्तावेज़ में paths, components या webhooks में से कम से कम एक होना चाहिए। OAS 3.1.1 विनिर्देश यही तय करता है।
इन्हीं शुरुआती पंक्तियों में एक फंदा छिपा है: openapi और info.version दो अलग चीज़ें हैं। पहला ख़ुद प्रारूप का संस्करण है, जिसे देखकर औज़ार तय करते हैं कि दस्तावेज़ को कैसे पढ़ना है। दूसरा आपके API का संस्करण है। विनिर्देश यह साफ़ शब्दों में कहता है, मगर सहज बुद्धि उल्टा सुझाती है — और इसी से openapi: 1.0 घोषित करने वाली फ़ाइलें पैदा होती हैं।
बड़े विनिर्देश आमतौर पर $ref के ज़रिये कई फ़ाइलों में बाँट दिए जाते हैं: मूल दस्तावेज़ ./paths/links.yaml की ओर इशारा करता है, और वह आगे ./schemas/link.yaml की ओर। सुविधाजनक है, और एक समस्या की जड़ भी, जिस पर मैं अंत में लौटूँगा।
OpenAPI और Swagger एक चीज़ नहीं हैं
इस विषय की सबसे आम उलझन यही है।
| यह क्या है | कौन सँभालता है | |
|---|---|---|
| OpenAPI | मानक ख़ुद, यानी प्रारूप | OpenAPI Initiative, Linux Foundation |
| Swagger | उस प्रारूप को पढ़ने वाले औज़ारों का समूह | SmartBear |
गड़बड़ी की वजह इतिहास में है। शुरू में Swagger विनिर्देश और औज़ार, दोनों को कहा जाता था। बाद में विनिर्देश OpenAPI Initiative को सौंप दिया गया और उसका नाम OpenAPI Specification हो गया, जबकि Swagger नाम औज़ारों के पास रह गया — Swagger UI, Swagger Editor वग़ैरह।
व्यवहार में "हम Swagger इस्तेमाल करते हैं" का मतलब लगभग हमेशा यही होता है कि "हमारे पास OpenAPI फ़ाइल है और हम उसे Swagger UI से दिखाते हैं"। दोनों आपस में बँधे हुए नहीं हैं: वही फ़ाइल Redoc में, Scalar में या किसी client generator में उतनी ही अच्छी तरह खुलती है।
संस्करण: 3.0, 3.1 और 3.2
शाखाओं के बीच का अंतर ऊपरी नहीं है।
3.0 आज भी सबसे ज़्यादा इस्तेमाल में है। इसकी कमज़ोरी data schema में है: वे JSON Schema जैसे दिखते हैं मगर उससे पूरी तरह संगत नहीं, और इससे औज़ारों का आपसी तालमेल बार-बार टूटता है।
3.1 ने यह खाई पाट दी। Schema object, JSON Schema Draft 2020-12 का अधिसमुच्चय बन गया, इसलिए जो schema आप पहले से JSON Schema में रखते हैं उन्हें दोबारा लिखने के बजाय सीधे काम में लाया जा सकता है। मौजूदा संशोधन 3.1.1 24 अक्टूबर 2024 को प्रकाशित हुआ।
3.2 सितंबर 2025 में आया। OpenAPI Initiative की घोषणा में सबसे उल्लेखनीय ये हैं:
querymethod, उन idempotent पठन के लिए जिनके parameter URL में नहीं समाते;- मानक से बाहर की method के लिए
additionalOperations; - streaming media प्रकार: Server-Sent Events, JSON Lines, JSON अनुक्रम;
summary,parentऔरkindके साथ श्रेणीबद्ध tag;- असुविधाजनक इनपुट वाले उपकरणों के लिए OAuth 2.0 device flow।
संस्करण सबसे बड़े अंक के हिसाब से नहीं, बल्कि इस हिसाब से चुनना चाहिए कि आपके औज़ार सचमुच किसे सँभालते हैं। पारिस्थितिकी में 3.1 का समर्थन मज़बूत है; 3.2 नया है और औज़ारों की शृंखला का एक हिस्सा अब भी उसे पकड़ रहा है। हमारा अपना विनिर्देश 3.1.0 घोषित करता है।
व्यवहार में इससे मिलता क्या है
एक ही फ़ाइल कई काम एक साथ निपटा देती है:
- संवादात्मक दस्तावेज़ — Swagger UI या Redoc सीधे फ़ाइल से पन्ना बना देते हैं, request आज़माने के फ़ॉर्म समेत;
- client library — generator आपकी भाषा में SDK निकाल देते हैं, हाथ से wrapper लिखने की ज़रूरत नहीं रहती;
- नकली server — backend बनने से पहले ही केवल विवरण के आधार पर mock खड़ा हो जाता है, और frontend को इंतज़ार नहीं करना पड़ता;
- contract परीक्षण — परीक्षण असली response को schema से भिड़ाते हैं और ठीक वह क्षण पकड़ लेते हैं जब response अपने विवरण से हटने लगता है।
OpenAPI के पक्ष में सबसे बड़ी दलील इसी सूची से निकलती है: दस्तावेज़ अब वह अलग लेख नहीं रह जाता जिसे अद्यतन करना कोई भूल जाए।
दलील सही है। बस वह अपने आप चलती नहीं।
विनिर्देश को कोड से कुछ भी नहीं जोड़ता
"OpenAPI क्या है" बताने वाले लेख इस हिस्से को लगभग कभी नहीं छूते, और असली माहौल में यही काटता है।
विनिर्देश फ़ाइल बस एक फ़ाइल है। Router को उसके होने की ख़बर नहीं। Controller को भी नहीं। आप कोई endpoint हटा सकते हैं, नया जोड़ सकते हैं, अनिवार्य field को वैकल्पिक बना सकते हैं — एक भी परीक्षण नहीं गिरेगा। दस्तावेज़ ख़ुद को समकालिक नहीं करता; वह ठीक तब तक सही रहता है जब तक कोई उसे सुधारना याद रखता है।
अंतर दोनों दिशाओं में बनता है, और हर दिशा अपने ढंग से नुक़सान करती है:
- लिखा है पर चलता नहीं। डेवलपर दस्तावेज़ पढ़कर request भेजता है और उसे 404 मिलता है। बाक़ी दस्तावेज़ पर भरोसा उसी पल ढह जाता है: यहाँ ग़लत था तो और कहाँ-कहाँ होगा?
- चलता है पर लिखा नहीं। जो उसे ढूँढ़ रहा है, उसके लिए वह सुविधा है ही नहीं। कोई उसे पाता नहीं, कोई उसके पैसे नहीं देता।
ज़्यादा ख़तरनाक दूसरा मामला है, क्योंकि कोई शिकायत नहीं करता। करने वाला ही नहीं होता: उपयोगकर्ता को पता ही नहीं कि वह endpoint मौजूद है।
हमारे साथ ठीक यही हुआ। Lix.li के API में conversion से जुड़े तीन endpoint बिलकुल ठीक चल रहे थे — घटनाओं की एक सूची, और postback लेने के दो रास्ते, एकल तथा समूह में — मगर उनमें से एक भी विनिर्देश में दर्ज नहीं था। कोड चल रहा था, परीक्षण पास हो रहे थे, और इस बीच API के परिचय पन्ने पर दो बिलकुल अलग path टँगे थे जो कोड में थे ही नहीं। यह बात किसी ख़राबी की सूचना से नहीं, पूरी जाँच-पड़ताल के दौरान सामने आई।
अंतर अपने आप पकड़ना
यह अनुशासन से नहीं, एक परीक्षण से हल होता है। विचार सीधा है: विनिर्देश से path की सूची लो, router से route की सूची लो, और दोनों समुच्चयों को दोनों दिशाओं में भिड़ाओ।
openapi.yaml के path → ऐसा route है? → नहीं तो दस्तावेज़ झूठ बोल रहा है
router के route → विनिर्देश में लिखा है? → नहीं तो सुविधा अदृश्य है
"जो लिखा है वह चलता है" वाला आधा हिस्सा असली request से जाँचना सबसे सुविधाजनक है: endpoint को बिना प्रमाण-पत्र के बुलाइए और पक्का कीजिए कि उत्तर 401 आए, 404 नहीं। यह फ़र्क़ मायने रखता है। 401 का मतलब है route मिल गया और वह कुंजी माँग रहा है; 404 का मतलब है ऐसा path है ही नहीं। इस दौरान कुछ भी लिखा नहीं जाता, क्योंकि प्रमाणीकरण controller से पहले चलता है।
उलटी दिशा की जाँच route की सेटिंग पढ़ लेती है। वह आपको अपवादों को स्पष्ट रूप से गिनाने पर भी मजबूर करती है — वे भीतरी endpoint जिनका सार्वजनिक अनुबंध में कोई काम नहीं। अपवादों की वह सूची अपने आप में क़ीमती है: वह आपसे एक बार, सोच-समझकर तय करवाती है कि आप किसे अपना सार्वजनिक API मानते हैं।
conversion वाले क़िस्से के बाद हमने यही परीक्षण लिखा। उसने अपनी क़ीमत तुरंत साबित कर दी: विनिर्देश से conversion दोबारा हटाइए, परीक्षण गिर जाता है और दोनों ग़ायब path का नाम लेकर बताता है।
दो फंदे जो देर से पता चलते हैं
$ref और सापेक्ष path। जब विनिर्देश कई फ़ाइलों में बँटा हो, उसके भीतर के संदर्भ उसी पते के सापेक्ष सुलझते हैं जहाँ से फ़ाइल परोसी गई। /openapi पर रखा मूल दस्तावेज़ ./paths/links.yaml को /paths/links.yaml पर ढूँढ़ेगा और कुछ नहीं पाएगा। ब्राउज़र में सब ठीक दिखता है, क्योंकि Swagger UI फ़ाइल को उसकी असली जगह से उठाता है — मगर उसी दस्तावेज़ पर लगाया गया client generator ठोकर खाएगा। या तो विनिर्देश को सिर्फ़ उसकी अपनी directory से परोसिए, या उसे बाहरी $ref रहित एक अकेली फ़ाइल में बाँध दीजिए।
खोजी रोबोट के लिए Swagger UI ख़ाली है। Swagger UI का पन्ना चंद पंक्तियों की markup और एक script भर है जो सामग्री ब्राउज़र में बनाता है। परोसे गए HTML में एक भी endpoint path नहीं होता। पढ़ने वाले के लिए पन्ना ठीक है; अनुक्रमण के लिहाज़ से कोरा है। इसमें robots.txt की एक आम भूल और जोड़ लीजिए: JSON endpoint छिपाने के लिए लिखा गया Disallow: /api/ नियम उसी उपसर्ग के नीचे बसे इंसानों वाले दस्तावेज़ को भी साथ छिपा देता है। रोकना चाहिए संस्करण सहित सटीक path को — मसलन /api/1.0/ — न कि पूरे हिस्से को।
शुरुआत कहाँ से करें
अगर API पहले से है और विवरण नहीं, तो क्रम मोटे तौर पर यह रहेगा:
- एक endpoint हाथ से लिखिए। बनावट समझने के लिए इतना काफ़ी है।
- वह संस्करण चुनिए जिसे आपके औज़ार बिना अटके सँभालते हों; तयशुदा तौर पर 3.1।
- फ़ाइल जब एक स्क्रीन में न समाए तब
$refसे बाँटिए, और उसी वक़्त तय कर लीजिए कि वह किस पते से परोसी जाएगी। - एक परीक्षण लगाइए जो विनिर्देश और router को दोनों दिशाओं में मिलाए। इस क़दम से पहले दस्तावेज़ के अद्यतन होने की हर बात वादा है, गुण नहीं।
असली API पर यह कैसा दिखता है, यह Lix.li के API दस्तावेज़ में देखा जा सकता है: वहाँ लिंक, समूह, A/B परीक्षण और conversion शामिल हैं। इस API के इर्द-गिर्द बनी सेवा के बारे में छोटे लिंक के API पन्ने पर पढ़ा जा सकता है। दो पड़ोसी विषय अलग से देखने लायक हैं: webhook, अगर आप घटनाएँ पूछने के बजाय पाना चाहते हैं, और 301, 302, 307, 308 redirect का फ़र्क़ — क्योंकि 301 POST को GET में बदल देता है, और यह बात ऊपर बताए गए postback endpoint से सीधे जुड़ती है।