एक उद्देश्यपूर्ण डिजाइन के लिए क्यों?
रेस्टफुल सिद्धांत वेब सेवाओं एपीआई डिजाइन के लिए वेब साइटों को आसान बनाने के लिए ( यादृच्छिक मानव उपयोगकर्ता के लिए "सर्फ" करने के लिए) सुविधाएँ लाते हैं , इसलिए वे प्रोग्रामर का उपयोग करना आसान है। REST अच्छा नहीं है क्योंकि यह REST है, यह अच्छा है क्योंकि यह अच्छा है। और यह ज्यादातर अच्छा है क्योंकि यह सरल है ।
सादा एचटीटीपी (एसओएपी लिफाफे और एकल-यूआरआई अतिभारित POST
सेवाओं के बिना) की सादगी , जिसे कुछ "सुविधाओं की कमी" कह सकते हैं , वास्तव में इसकी सबसे बड़ी ताकत है । बल्ले से सही, HTTP आपसे पते की अक्षमता और स्टेटलेसनेस के लिए कहता है : दो मूल डिज़ाइन निर्णय जो HTTP को आज की मेगा-साइट्स (और मेगा-सर्विसेज) तक बनाए रखते हैं।
लेकिन REST सिल्वर बुलट नहीं है: कभी-कभी एक RPC- शैली ("रिमोट प्रक्रिया कॉल" - जैसे SOAP) उपयुक्त हो सकती है , और कभी-कभी अन्य आवश्यकताओं को वेब के गुणों पर पूर्वता प्राप्त होती है। यह ठीक है। जो हमें वास्तव में पसंद नहीं है, वह है अनावश्यक जटिलता । अक्सर एक प्रोग्रामर या एक कंपनी एक नौकरी के लिए आरपीसी-शैली सेवाओं को लाती है जो सादे पुराने एचटीटीपी को ठीक से संभाल सकती है। इसका प्रभाव यह है कि HTTP एक विशाल XML पेलोड के लिए परिवहन प्रोटोकॉल में कम हो गया है, जो बताता है कि "वास्तव में" क्या चल रहा है (URI या HTTP विधि इसके बारे में कोई सुराग नहीं देता है)। परिणामी सेवा अब तक बहुत जटिल है, डिबग करना असंभव है, और तब तक काम नहीं करेगा जब तक कि आपके क्लाइंट का डेवलपर के अनुसार सटीक सेटअप न हो ।
उसी तरह एक जावा / सी # कोड ऑब्जेक्ट-ओरिएंटेड नहीं हो सकता है , बस एचटीटीपी का उपयोग करने से एक डिज़ाइन रेस्टफुल नहीं बनता है। एक को कार्रवाई और दूरदराज के तरीकों के बारे में उनकी सेवाओं के बारे में सोचने की हड़बड़ी में पकड़ा जा सकता है जिन्हें बुलाया जाना चाहिए। कोई आश्चर्य नहीं कि यह ज्यादातर आरपीसी-स्टाइल सेवा (या आरईएसटी-आरपीसी-हाइब्रिड) में समाप्त होगा। पहला कदम अलग तरीके से सोचना है। एक शानदार डिजाइन कई तरीकों से प्राप्त किया जा सकता है, एक तरीका संसाधनों के संदर्भ में आपके आवेदन के बारे में सोचना है, न कि कार्य:
💡 कार्यों के संदर्भ में सोचने के बजाय यह प्रदर्शन कर सकता है ("मानचित्र पर स्थानों की खोज करें") ...
... उन कार्यों के परिणामों के बारे में सोचने की कोशिश करें ("मानचित्र पर स्थानों की सूची एक खोज मापदंड से मेल खाती है")।
मैं नीचे के उदाहरणों के लिए जाऊँगा। (REST का अन्य मुख्य पहलू HATEOAS का उपयोग है - मैं इसे यहाँ ब्रश नहीं करता, लेकिन मैं इसके बारे में किसी भी पोस्ट पर जल्दी से बात करता हूं ।)
पहले डिजाइन के मुद्दे
आइए एक नज़र डालते हैं प्रस्तावित डिजाइन:
ACTION http://api.animals.com/v1/dogs/1/
सबसे पहले, हमें एक नया HTTP वर्ब ( ACTION
) बनाने पर विचार नहीं करना चाहिए । सामान्यतया, यह कई कारणों से अवांछनीय है:
- (1) केवल सेवा URI को देखते हुए, "यादृच्छिक" प्रोग्रामर को पता चलेगा कि
ACTION
क्रिया कैसे मौजूद है?
- (२) यदि प्रोग्रामर जानता है कि यह मौजूद है, तो वह इसके शब्दार्थ को कैसे जान पाएगा? उस क्रिया का क्या अर्थ है?
- (३) क्या गुण (सुरक्षा, मूर्खता) किसी को उस क्रिया की अपेक्षा करनी चाहिए?
- (4) क्या होगा यदि प्रोग्रामर के पास एक बहुत ही सरल क्लाइंट है जो केवल मानक HTTP क्रियाओं को संभालता है?
- (५) ...
अब आइए उपयोग करने पर विचार करेंPOST
(मैं चर्चा करूंगा कि नीचे क्यों, अभी इसके लिए मेरा शब्द लें):
POST /v1/dogs/1/ HTTP/1.1
Host: api.animals.com
{"action":"bark"}
यह ठीक हो सकता है ... लेकिन केवल अगर :
{"action":"bark"}
एक दस्तावेज था; तथा
/v1/dogs/1/
एक "दस्तावेज़ प्रोसेसर" (कारखाना जैसा) यूआरआई था। एक "डॉक्यूमेंट प्रोसेसर" एक यूआरआई है जिसे आप केवल "चीजों को फेंक" देते हैं और उनके बारे में "भूल जाते हैं" - प्रोसेसर आपको "फेंकने" के बाद एक नए बनाए गए संसाधन पर पुनर्निर्देशित कर सकता है। उदाहरण के लिए URI एक संदेश ब्रोकर सेवा पर संदेश पोस्ट करने के लिए, जो कि पोस्ट करने के बाद आपको URI के लिए पुनर्निर्देशित करेगा जो संदेश के प्रसंस्करण की स्थिति दिखाता है।
मुझे आपके सिस्टम के बारे में ज्यादा जानकारी नहीं है, लेकिन मैं शर्त लगा सकता हूं कि दोनों सच नहीं हैं:
{"action":"bark"}
कोई दस्तावेज़ नहीं है , यह वास्तव में वह तरीका है जिसे आप सेवा में निंजा-चुपके की कोशिश कर रहे हैं ; तथा
/v1/dogs/1/
यूआरआइ एक "कुत्ता" संसाधन (शायद के साथ कुत्ते का प्रतिनिधित्व करता है id==1
) और नहीं एक दस्तावेज प्रोसेसर।
तो अब हम जानते हैं कि ऊपर का डिज़ाइन इतना Restful नहीं है, लेकिन वास्तव में ऐसा क्या है? इसके बारे में इतना बुरा क्या है? मूल रूप से, यह बुरा है क्योंकि जटिल URI जटिल अर्थों के साथ है। आप इससे कुछ भी अनुमान नहीं लगा सकते। एक प्रोग्रामर को कैसे पता चलेगा कि एक कुत्ते के पास एक ऐसी bark
कार्रवाई है जिसे गुप्त रूप से एक साथ संक्रमित किया जा सकता POST
है?
अपने प्रश्न के एपीआई कॉल को डिजाइन करना
तो चलो पीछा करने के लिए कटौती करते हैं और संसाधनों के संदर्भ में सोचकर उन छालों को डिजाइन करने का प्रयास करते हैं । मुझे रेस्टफुल वेब सेवा पुस्तक को उद्धृत करने की अनुमति दें :
एक POST
अनुरोध पहले से मौजूद किसी से एक नया संसाधन पैदा करने की कोशिश है। मौजूदा संसाधन डेटा-संरचना अर्थों में नए के माता-पिता हो सकते हैं, जिस तरह से एक पेड़ की जड़ उसके सभी पत्तों के नोड्स के माता-पिता हैं। या मौजूदा संसाधन एक विशेष "कारखाना" संसाधन हो सकता है
जिसका एकमात्र उद्देश्य अन्य संसाधनों को उत्पन्न करना है। POST
अनुरोध के साथ भेजा गया प्रतिनिधित्व नए संसाधन की प्रारंभिक स्थिति का वर्णन करता है। PUT के साथ, एक POST
अनुरोध को सभी में एक प्रतिनिधित्व शामिल करने की आवश्यकता नहीं है।
ऊपर दिए गए विवरण के बाद हम देख सकते हैं कि bark
इसे एक के उप-स्रोत केdog
रूप में तैयार किया जा सकता है (क्योंकि bark
यह एक कुत्ते के भीतर निहित है, अर्थात, एक कुत्ते द्वारा छाल "छाल" है )।
उस तर्क से हम पहले ही मिल गए:
- विधि है
POST
- संसाधन है
/barks
, कुत्ते का उप- स्रोत : "कारखाने" का /v1/dogs/1/barks
प्रतिनिधित्व करना bark
। यह URI प्रत्येक कुत्ते के लिए अद्वितीय है (क्योंकि यह नीचे है /v1/dogs/{id}
)।
अब आपकी सूची के प्रत्येक मामले का एक विशिष्ट व्यवहार है।
1. छाल सिर्फ ई-मेल भेजता है dog.email
और कुछ भी रिकॉर्ड नहीं करता है।
सबसे पहले, एक ई-मेल भेजना (एक ई-मेल भेजना) एक समकालिक या एक अतुल्यकालिक कार्य है? दूसरे bark
अनुरोध में किसी भी दस्तावेज़ (ई-मेल, शायद) की आवश्यकता होती है या क्या यह खाली है?
1.1 छाल एक ई-मेल भेजता है dog.email
और कुछ भी रिकॉर्ड नहीं करता है (एक तुल्यकालिक कार्य के रूप में)
यह मामला सरल है। barks
फैक्ट्री रिसोर्स पर कॉल करने पर तुरंत एक बार्क (एक ई-मेल भेजा गया) और रिस्पॉन्स मिलता है (यदि ठीक है या नहीं) तुरंत दिया जाता है:
POST /v1/dogs/1/barks HTTP/1.1
Host: api.animals.com
Authorization: Basic mAUhhuE08u724bh249a2xaP=
(entity-body is empty - or, if you require a **document**, place it here)
200 OK
जैसा कि यह रिकॉर्ड (परिवर्तन) कुछ भी नहीं है, 200 OK
पर्याप्त है। यह दिखाता है कि सब कुछ उम्मीद के मुताबिक चला।
1.2 छाल एक ई-मेल भेजता है dog.email
और कुछ भी रिकॉर्ड नहीं करता है (एक अतुल्यकालिक कार्य के रूप में)
इस स्थिति में, क्लाइंट के पास bark
कार्य को ट्रैक करने का एक तरीका होना चाहिए । इसके bark
बाद कार्य यूआईआरआई के पास होना चाहिए।
POST /v1/dogs/1/barks HTTP/1.1
Host: api.animals.com
Authorization: Basic mAUhhuE08u724bh249a2xaP=
{document body, if needed;
NOTE: when possible, the response SHOULD contain a short hypertext note with a hyperlink
to the newly created resource (bark) URI, the same returned in the Location header
(also notice that, for the 202 status code, the Location header meaning is not
standardized, thus the importance of a hipertext/hyperlink response)}
202 Accepted
Location: http://api.animals.com/v1/dogs/1/barks/a65h44
इस तरह, प्रत्येक bark
ट्रेस करने योग्य है। क्लाइंट तब यह जानने के GET
लिए bark
URI को जारी कर सकता है कि यह वर्तमान स्थिति है। शायद DELETE
इसे रद्द करने के लिए भी उपयोग करें ।
2. छाल एक ई-मेल भेजती है dog.email
और फिर dog.barkCount
1 से बढ़ जाती है
यह एक dog
मुश्किल हो सकता है, यदि आप ग्राहक को यह बताना चाहते हैं कि संसाधन बदल जाता है:
POST /v1/dogs/1/barks HTTP/1.1
Host: api.animals.com
Authorization: Basic mAUhhuE08u724bh249a2xaP=
{document body, if needed; when possible, containing a hipertext/hyperlink with the address
in the Location header -- says the standard}
303 See Other
Location: http://api.animals.com/v1/dogs/1
इस मामले में, location
हेडर का इरादा ग्राहक को यह बताने का है कि उसे एक नज़र रखना चाहिए dog
। से के बारे में HTTP आरएफसी303
:
यह विधि मुख्य रूप से एक चयनित संसाधन के लिए उपयोगकर्ता एजेंट को पुनर्निर्देशित करने के लिए एक POST
निष्क्रिय स्क्रिप्ट के आउटपुट की अनुमति देने के लिए मौजूद है
।
यदि कार्य अतुल्यकालिक है, bark
तो 1.2
स्थिति की तरह ही एक सबस्रोत की आवश्यकता होती है और जब कार्य पूरा हो जाता है, तो 303
उसे लौटा दिया जाना चाहिए GET .../barks/Y
।
3. छाल रिकॉर्डिंग के bark
साथ एक नया रिकॉर्ड बनाता है bark.timestamp
जब छाल ठीक हो जाती है। यह भी dog.barkCount
1 से बढ़ा है।
POST /v1/dogs/1/barks HTTP/1.1
Host: api.animals.com
Authorization: Basic mAUhhuE08u724bh249a2xaP=
(document body, if needed)
201 Created
Location: http://api.animals.com/v1/dogs/1/barks/a65h44
यहां, bark
अनुरोध के कारण बनाया गया है, इसलिए स्थिति 201 Created
लागू होती है।
यदि सृजन अतुल्यकालिक है, तो इसके बजाय एक 202 Accepted
आवश्यक है ( जैसा कि HTTP RFC कहता है )।
बचाया गया टाइमस्टैम्प bark
संसाधन का एक हिस्सा है और GET
इसे इसके साथ पुनः प्राप्त किया जा सकता है। अद्यतन किए गए कुत्ते को उसी GET dogs/X/barks/Y
रूप में "प्रलेखित" किया जा सकता है ।
4. छाल गितुब से कुत्ते कोड के नवीनतम संस्करण को खींचने के लिए एक सिस्टम कमांड चलाता है। यह तब dog.owner
उन्हें यह बताने के लिए एक पाठ संदेश भेजता है कि नया कुत्ता कोड उत्पादन में है।
इस एक का शब्दांकन जटिल है, लेकिन यह बहुत सरल है अतुल्यकालिक कार्य:
POST /v1/dogs/1/barks HTTP/1.1
Host: api.animals.com
Authorization: Basic mAUhhuE08u724bh249a2xaP=
(document body, if needed)
202 Accepted
Location: http://api.animals.com/v1/dogs/1/barks/a65h44
क्लाइंट तब वर्तमान स्थिति को जानने के GET
लिए जारी करेगा /v1/dogs/1/barks/a65h44
(यदि कोड खींचा गया था, तो यह ई-मेल स्वामी को भेजा गया था और ऐसे)। जब भी कुत्ता बदलता है, एक 303
सराहनीय है।
समेट रहा हु
रॉय फील्डिंग का हवाला देते हुए :
REST के तरीकों की एकमात्र आवश्यकता यह है कि उन्हें सभी संसाधनों के लिए समान रूप से परिभाषित किया जाए (यानी, ताकि मध्यस्थों को अनुरोध के अर्थ को समझने के लिए संसाधन प्रकार का पता न चले)।
उपरोक्त उदाहरणों में, POST
समान रूप से डिज़ाइन किया गया है। यह कुत्ते को बना देगा " bark
"। यह सुरक्षित नहीं है (मतलब छाल का संसाधनों पर प्रभाव पड़ता है), और न ही बेकार (प्रत्येक अनुरोध एक नई पैदावार देता है bark
), जो POST
क्रिया को अच्छी तरह से फिट बैठता है ।
एक प्रोग्रामर को पता होगा: ए POST
से barks
पैदावार ए bark
। प्रतिक्रिया स्थिति कोड (आवश्यक होने पर निकाय-निकाय और हेडर के साथ भी) यह समझाने का काम करते हैं कि ग्राहक क्या बदला और कैसे आगे बढ़ना चाहिए।
नोट: उपयोग किए जाने वाले प्राथमिक स्रोत थे: " रेस्टफुल वेब सर्विसेज " पुस्तक, HTTP RFC और रॉय फील्डिंग का ब्लॉग ।
संपादित करें:
सवाल और इस तरह जवाब काफी बदल गया है क्योंकि वे पहली बार बनाए गए थे। मूल प्रश्न यूआरआई तरह के डिजाइन के बारे में पूछा:
ACTION http://api.animals.com/v1/dogs/1/?action=bark
नीचे यह स्पष्टीकरण दिया गया है कि यह एक अच्छा विकल्प क्यों नहीं है:
क्लाइंट डेटा के साथ WHAT TO DO को कैसे बताते हैं, यह विधि की जानकारी है ।
- Restful वेब सेवाएं HTTP मेथड में सूचना को बताती हैं।
- विशिष्ट RPC- शैली और SOAP सेवाएँ इकाई-निकाय और HTTP शीर्ष लेख में अपना स्थान रखती हैं।
डेटा का हिस्सा [क्लाइंट को सर्वर चाहिए] जिस पर काम करना है, वह है स्कॉपिंग जानकारी ।
- श्रेष्ठ सेवाएँ URI का उपयोग करती हैं। SOAP / RPC- शैली सेवाएँ एक बार फिर निकाय-निकाय और HTTP हेडर का उपयोग करती हैं।
एक उदाहरण के रूप में, Google का URI लें http://www.google.com/search?q=DOG
। वहां, विधि की जानकारी है GET
और स्कूपिंग जानकारी है /search?q=DOG
।
कहानी संक्षिप्त में:
- में RESTful आर्किटेक्चर , विधि जानकारी HTTP विधि में चला जाता है।
- में संसाधन उन्मुख आर्किटेक्चर , scoping जानकारी यूआरआई में चला जाता है।
और अंगूठे का नियम:
यदि HTTP विधि विधि की जानकारी से मेल नहीं खाती है, तो सेवा Restful नहीं है। यदि स्कोपिंग जानकारी URI में नहीं है, तो सेवा संसाधन-उन्मुख नहीं है।
आप "छाल" "क्रिया" को URL (या निकाय-निकाय) में डाल सकते हैं और उपयोग कर सकते हैं POST
। वहाँ कोई समस्या नहीं है, यह काम करता है, और यह करने का सबसे सरल तरीका हो सकता है, लेकिन यह रेस्टफुल नहीं है ।
वास्तव में अपनी सेवा को बनाए रखने के लिए, आपको एक कदम पीछे ले जाना होगा और सोचना होगा कि आप वास्तव में यहां क्या करना चाहते हैं (संसाधनों पर इसका क्या प्रभाव पड़ेगा)।
मैं आपकी विशिष्ट व्यावसायिक आवश्यकताओं के बारे में बात नहीं कर सकता, लेकिन मैं आपको एक उदाहरण देता हूं: एक RESTful ऑर्डरिंग सेवा पर विचार करें, जहां URI जैसे ऑर्डर हैं example.com/order/123
।
अब कहते हैं कि हम एक आदेश रद्द करना चाहते हैं, हम इसे कैसे करने जा रहे हैं? किसी को यह सोचने के लिए लुभाया जा सकता है कि यह "रद्द करना" "कार्रवाई" है और इसे डिजाइन करना POST example.com/order/123?do=cancel
।
यह Restful नहीं है, जैसा कि हमने ऊपर बात की है। इसके बजाय, हम भेजे गए तत्व PUT
के order
साथ एक नया प्रतिनिधित्व कर सकते हैं :canceled
true
PUT /order/123 HTTP/1.1
Content-Type: application/xml
<order id="123">
<customer id="89987">...</customer>
<canceled>true</canceled>
...
</order>
और बस। यदि आदेश रद्द नहीं किया जा सकता है, तो एक विशिष्ट स्थिति कोड वापस किया जा सकता है। ( सादगी के लिए POST /order/123/canceled
इकाई-निकाय के साथ एक सबसोर्स डिज़ाइन true
भी उपलब्ध हो सकता है।)
अपने विशिष्ट परिदृश्य में, आप कुछ इसी तरह की कोशिश कर सकते हैं। इस तरह से, जबकि एक कुत्ते भौंकने है, उदाहरण के लिए, एक GET
पर /v1/dogs/1/
है कि जानकारी शामिल हो सकते हैं (उदाहरण के लिए <barking>true</barking>
) । या ... अगर वह बहुत जटिल है, तो अपनी आवश्यकता को पूरा करें और साथ रहें POST
।
अपडेट करें:
मैं उत्तर को बहुत बड़ा नहीं बनाना चाहता, लेकिन एक एल्गोरिथ्म (एक क्रिया ) को संसाधनों के एक समूह के रूप में उजागर करने के हैंग होने में थोड़ा समय लगता है । कार्यों के संदर्भ में सोचने के बजाय ( "मानचित्र पर स्थानों की खोज करें" ), किसी को उस कार्रवाई के परिणामों के बारे में सोचने की आवश्यकता है ( "खोज मानदंडों से मेल खाते मानचित्र पर स्थानों की सूची" )।
यदि आप पाते हैं कि आपका डिज़ाइन HTTP के एकसमान इंटरफ़ेस के अनुकूल नहीं है, तो आप अपने आप को इस चरण पर वापस आ सकते हैं।
क्वेरी चर जानकारी दे रहे हैं , लेकिन नए संसाधनों को निरूपित नहीं करते ( यह स्पष्ट रूप से एक ही संसाधन है , बस एक अलग प्रतिनिधित्व)। बल्कि, वे संप्रेषित करने के लिए उपयोग किया जाता है ग्राहक राज्य (जैसे ;, ताकि राज्य सर्वर में रखा नहीं है भी एक उदाहरण यहाँ है) या इनपुट पैरामीटर के लिए एल्गोरिथम संसाधनों ( , )। फिर, अलग संसाधन नहीं।/post?lang=en
/post?lang=jp
?page=10
?lang=en
/search?q=dogs
/dogs?code=1
HTTP क्रिया '(विधियाँ) गुण:
एक अन्य स्पष्ट बिंदु जो ?action=something
यूआरआई में प्रदर्शित होता है, रेस्टफुल नहीं है, HTTP क्रिया के गुण हैं:
GET
और HEAD
सुरक्षित हैं (और बेकार);
PUT
और DELETE
केवल बेरोजगार हैं;
POST
नहीं है।
सुरक्षा : कुछ डेटा को पढ़ने के लिए अनुरोध GET
या HEAD
अनुरोध , किसी सर्वर स्थिति को बदलने का अनुरोध नहीं है। ग्राहक 10 बार अनुरोध या अनुरोध कर सकता है और इसे एक बार बनाने के समान है, या इसे कभी भी नहीं बना सकता है ।GET
HEAD
Idempotence : एक में एक आदर्श ऑपरेशन, जिसका एक ही प्रभाव है कि क्या आप इसे एक बार या एक से अधिक बार लागू करते हैं (गणित में, शून्य से गुणा करना idempotent है)। यदि आप DELETE
एक बार संसाधन करते हैं, तो फिर से हटाने का एक ही प्रभाव होगा (संसाधन GONE
पहले से ही है)।
POST
न तो सुरक्षित है और न ही बेकार है। POST
'फ़ैक्टरी' संसाधन के लिए दो समान अनुरोध करने से संभवतः दो अधीनस्थ संसाधनों में एक ही जानकारी होगी। अतिभारित (यूआरआई या इकाई-निकाय में विधि) के साथ POST
, सभी दांव बंद हैं।
ये दोनों गुण HTTP प्रोटोकॉल (अविश्वसनीय नेटवर्क पर) की सफलता के लिए महत्वपूर्ण थे: आपने कितनी बार अपडेट किया है ( GET
) पृष्ठ को प्रतीक्षा किए बिना जब तक यह पूरी तरह से लोड नहीं हो जाता?
एक क्रिया बनाना और URL में रखने से स्पष्ट रूप से HTTP विधियों का अनुबंध टूट जाता है। एक बार फिर, तकनीक आपको अनुमति देती है, आप इसे कर सकते हैं, लेकिन यह Restful डिजाइन नहीं है।