एक उद्देश्यपूर्ण डिजाइन के लिए क्यों?
रेस्टफुल सिद्धांत वेब सेवाओं एपीआई डिजाइन के लिए वेब साइटों को आसान बनाने के लिए ( यादृच्छिक मानव उपयोगकर्ता के लिए "सर्फ" करने के लिए) सुविधाएँ लाते हैं , इसलिए वे प्रोग्रामर का उपयोग करना आसान है। 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लिए barkURI को जारी कर सकता है कि यह वर्तमान स्थिति है। शायद DELETEइसे रद्द करने के लिए भी उपयोग करें ।
2. छाल एक ई-मेल भेजती है dog.emailऔर फिर dog.barkCount1 से बढ़ जाती है
यह एक 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.barkCount1 से बढ़ा है।
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साथ एक नया प्रतिनिधित्व कर सकते हैं :canceledtrue
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 बार अनुरोध या अनुरोध कर सकता है और इसे एक बार बनाने के समान है, या इसे कभी भी नहीं बना सकता है ।GETHEAD
Idempotence : एक में एक आदर्श ऑपरेशन, जिसका एक ही प्रभाव है कि क्या आप इसे एक बार या एक से अधिक बार लागू करते हैं (गणित में, शून्य से गुणा करना idempotent है)। यदि आप DELETEएक बार संसाधन करते हैं, तो फिर से हटाने का एक ही प्रभाव होगा (संसाधन GONEपहले से ही है)।
POSTन तो सुरक्षित है और न ही बेकार है। POST'फ़ैक्टरी' संसाधन के लिए दो समान अनुरोध करने से संभवतः दो अधीनस्थ संसाधनों में एक ही जानकारी होगी। अतिभारित (यूआरआई या इकाई-निकाय में विधि) के साथ POST, सभी दांव बंद हैं।
ये दोनों गुण HTTP प्रोटोकॉल (अविश्वसनीय नेटवर्क पर) की सफलता के लिए महत्वपूर्ण थे: आपने कितनी बार अपडेट किया है ( GET) पृष्ठ को प्रतीक्षा किए बिना जब तक यह पूरी तरह से लोड नहीं हो जाता?
एक क्रिया बनाना और URL में रखने से स्पष्ट रूप से HTTP विधियों का अनुबंध टूट जाता है। एक बार फिर, तकनीक आपको अनुमति देती है, आप इसे कर सकते हैं, लेकिन यह Restful डिजाइन नहीं है।