REST API - एकल अनुरोध में बल्क बनाएं या अपडेट करें [बंद]


94

मान लेते हैं कि दो संसाधन हैं Binderऔर Docसंगति संबंध का अर्थ है कि Docऔर Binderअपने दम पर खड़े हों। Docहो सकता है या नहीं हो सकता है Binderऔर Binderखाली हो सकता है।

अगर मैं एक REST API डिजाइन करना चाहता हूं, जो उपयोगकर्ता को निम्नलिखित की तरह, DocS, IN SINGLE REQUEST के संग्रह को भेजने की अनुमति देता है :

{
  "docs": [
    {"doc_number": 1, "binder": 1}, 
    {"doc_number": 5, "binder": 8},
    {"doc_number": 6, "binder": 3}
  ]
}

और में प्रत्येक दस्तावेज़ के लिए docs,

  • यदि docमौजूद है तो उसे असाइन करेंBinder
  • यदि docमौजूद नहीं है, तो इसे बनाएं और फिर असाइन करें

मैं वास्तव में उलझन में हूँ कि इसे कैसे लागू किया जाना चाहिए:

  • क्या HTTP विधि का उपयोग करने के लिए?
  • क्या प्रतिक्रिया कोड लौटाया जाना चाहिए?
  • क्या यह REST के लिए भी योग्य है?
  • URI कैसा दिखेगा? /binders/docs?
  • थोक अनुरोध को संभालना, क्या होगा अगर कुछ आइटम एक त्रुटि उठाते हैं लेकिन दूसरे से गुजरते हैं। क्या प्रतिक्रिया कोड लौटाया जाना चाहिए? क्या थोक संचालन परमाणु होना चाहिए?

जवाबों:


59

मुझे लगता है कि आप इसे संभालने के लिए एक POST या PATCH विधि का उपयोग कर सकते हैं क्योंकि वे आम तौर पर इसके लिए डिज़ाइन करते हैं।

  • किसी POSTविधि का उपयोग करना आमतौर पर सूची संसाधन पर उपयोग किए जाने पर एक तत्व जोड़ने के लिए किया जाता है, लेकिन आप इस विधि के लिए कई क्रियाओं का समर्थन भी कर सकते हैं। इस उत्तर को देखें: एक रिसोर्स रिसोर्स कलेक्शन को कैसे अपडेट करें । आप इनपुट के लिए विभिन्न प्रतिनिधित्व स्वरूपों का भी समर्थन कर सकते हैं (यदि वे किसी सरणी या एकल तत्वों के अनुरूप हैं)।

    मामले में, अपडेट का वर्णन करने के लिए अपने प्रारूप को परिभाषित करना आवश्यक नहीं है।

  • एक PATCHविधि का उपयोग करना भी उपयुक्त है क्योंकि संबंधित अनुरोध आंशिक अद्यतन के अनुरूप हैं। RFC5789 ( http://tools.ietf.org/html/rfc5789 ) के अनुसार :

    हाइपरटेक्स्ट ट्रांसफर प्रोटोकॉल (HTTP) को बढ़ाने वाले कई एप्लिकेशन को आंशिक संसाधन संशोधन करने के लिए एक सुविधा की आवश्यकता होती है। मौजूदा HTTP PUT विधि केवल एक दस्तावेज़ के पूर्ण प्रतिस्थापन की अनुमति देती है। यह प्रस्ताव एक मौजूदा HTTP संसाधन को संशोधित करने के लिए एक नया HTTP विधि, PATCH जोड़ता है।

    मामले में, आपको आंशिक अद्यतन का वर्णन करने के लिए अपने प्रारूप को परिभाषित करना होगा।

मुझे लगता है कि इस मामले में, POSTऔर PATCHकाफी समान हैं क्योंकि आपको वास्तव में प्रत्येक तत्व के लिए ऑपरेशन का वर्णन करने की आवश्यकता नहीं है। मैं कहूंगा कि यह भेजने के लिए प्रतिनिधित्व के प्रारूप पर निर्भर करता है।

का मामला PUTथोड़ा कम स्पष्ट है। वास्तव में, एक विधि का उपयोग करते समय PUT, आपको पूरी सूची प्रदान करनी चाहिए। वास्तव में, अनुरोध में प्रदत्त प्रतिनिधित्व सूची संसाधन एक के प्रतिस्थापन में होगा।

संसाधन पथ के संबंध में आपके पास दो विकल्प हो सकते हैं।

  • डॉक्टर सूची के लिए संसाधन पथ का उपयोग करना

इस मामले में, आपको सामूहिक रूप से अनुरोध में प्रदान किए गए प्रतिनिधित्व में एक बाइंडर के साथ डॉक्स की लिंक प्रदान करने की आवश्यकता है।

इसके लिए यहां एक नमूना मार्ग है /docs

इस तरह के दृष्टिकोण की सामग्री विधि के लिए हो सकती है POST:

[
    { "doc_number": 1, "binder": 4, (other fields in the case of creation) },
    { "doc_number": 2, "binder": 4, (other fields in the case of creation) },
    { "doc_number": 3, "binder": 5, (other fields in the case of creation) },
    (...)
]
  • बाइंडर तत्व के उप संसाधन पथ का उपयोग करना

इसके अलावा आप डॉक्स और बाइंडरों के बीच लिंक का वर्णन करने के लिए उप मार्गों का लाभ उठाने पर भी विचार कर सकते हैं। एक डॉक्टर और एक बांधने की मशीन के बीच संबंध के संकेत अब अनुरोध सामग्री के भीतर निर्दिष्ट करने के लिए नहीं है।

इसके लिए यहां एक नमूना मार्ग है /binder/{binderId}/docs। इस स्थिति में, किसी विधि के साथ डॉक्स की सूची भेजना POSTया PATCHडॉक्स को पहचानकर्ता के साथ बांधने वाले के साथ संलग्न करना होगा binderIdजब वह मौजूद नहीं है तो डॉक्टर को बनाया है।

इस तरह के दृष्टिकोण की सामग्री विधि के लिए हो सकती है POST:

[
    { "doc_number": 1, (other fields in the case of creation) },
    { "doc_number": 2, (other fields in the case of creation) },
    { "doc_number": 3, (other fields in the case of creation) },
    (...)
]

प्रतिक्रिया के बारे में, प्रतिक्रिया के स्तर और वापसी की त्रुटियों को परिभाषित करना आपके ऊपर है। मुझे दो स्तर दिखाई देते हैं: स्थिति स्तर (वैश्विक स्तर) और पेलोड स्तर (पतले स्तर)। यह आपके ऊपर निर्भर है कि आपके अनुरोध के अनुरूप सभी आवेषण / अपडेट परमाणु होने चाहिए या नहीं।

  • परमाणु

इस स्थिति में, आप HTTP स्थिति का लाभ उठा सकते हैं। अगर सबकुछ ठीक हो जाता है, तो आपको एक दर्जा मिलता है 200। यदि नहीं, तो एक अन्य स्थिति जैसे 400कि प्रदान किया गया डेटा सही नहीं है (उदाहरण के लिए बाइंडर आईडी मान्य नहीं है) या कुछ और।

  • गैर परमाणु

इस स्थिति में, एक स्थिति 200वापस आ जाएगी और यह प्रतिक्रिया प्रतिनिधित्व पर निर्भर है कि क्या किया गया था और आखिरकार त्रुटियां कहां हुईं। ElasticSearch के बल्क अपडेट के लिए इसके REST API में एक समापन बिंदु है। यह आपको इस स्तर पर कुछ विचार दे सकता है: http://www.elasticsearch.org/guide/en/elasticsearch/guide/current/bulk.html

  • अतुल्यकालिक

आप प्रदान किए गए डेटा को संभालने के लिए एक अतुल्यकालिक प्रसंस्करण को भी लागू कर सकते हैं। इस स्थिति में, HTTP स्थिति रिटर्न होगा 202। क्लाइंट को यह देखने के लिए एक अतिरिक्त संसाधन खींचने की आवश्यकता है कि क्या होता है।

खत्म करने से पहले, मैं यह भी नोटिस करना चाहता हूं कि ओडटा विनिर्देश नेविगेशन लिंक नाम की सुविधा के साथ संस्थाओं के बीच संबंधों के मुद्दे को संबोधित करता है । शायद तुम इस पर एक नज़र हो सकता है ;-)

निम्नलिखित लिंक भी आपकी मदद कर सकते हैं: https://templth.wordpress.com/2014/12/15/designing-a-web-api/

आशा है कि यह आपकी मदद करता है, थियरी


मेरे पास सवाल है। मैंने बिना नेस्टेड रिसोर्स के बिना सपाट मार्गों का विकल्प चुना। सभी डॉक्स प्राप्त करने के लिए, मैं GET /docsएक विशेष बाइंडर के भीतर सभी डॉक्स को कॉल और पुनः प्राप्त करता हूं GET /docs?binder_id=x। हटाने के लिए संसाधनों का एक सबसेट मैं कहेंगे DELETE /docs?binder_id=xया मैं फोन करना चाहिए DELETE /docsएक साथ {"binder_id": x}अनुरोध शरीर में? क्या आप कभी PATCH /docs?binder_id=xबैच अपडेट के लिए उपयोग करेंगे , या सिर्फ PATCH /docsऔर जोड़े पास करेंगे?
एंडी फ्यूज़निएक

35

आपको संभवतः POST या PATCH का उपयोग करने की आवश्यकता होगी, क्योंकि यह संभावना नहीं है कि एक एकल अनुरोध जो अद्यतन करता है और कई संसाधन बनाता है, वह बेरोजगार होगा।

करना PATCH /docsनिश्चित रूप से एक वैध विकल्प है। आप अपने विशेष परिदृश्य के लिए पेचीदा पैच फॉरमेट का उपयोग कर सकते हैं। इस बारे में निश्चित नहीं है।

आप 200 का उपयोग कर सकते हैं। आप 207 का उपयोग भी कर सकते हैं - मल्टी स्टेटस

इसे RESTful तरीके से किया जा सकता है। मेरी राय में, कुंजी के पास कुछ संसाधन हैं जिन्हें अद्यतन / बनाने के लिए दस्तावेजों के एक सेट को स्वीकार करने के लिए डिज़ाइन किया गया है।

यदि आप पाट विधि का उपयोग करते हैं तो मुझे लगता है कि आपका ऑपरेशन परमाणु होना चाहिए। यानी मैं 207 स्थिति कोड का उपयोग नहीं करूंगा और फिर प्रतिक्रिया निकाय में सफलताओं और विफलताओं की रिपोर्ट करूंगा। यदि आप POST ऑपरेशन का उपयोग करते हैं तो 207 दृष्टिकोण व्यवहार्य है। आपको यह संचार करने के लिए अपनी स्वयं की प्रतिक्रिया देनी होगी कि कौन सा ऑपरेशन सफल हुआ और कौन सा विफल रहा। मैं एक मानकीकृत के बारे में पता नहीं हूँ।


बहुत बहुत धन्यवाद। तक This can be done in a RESTful wayआप अद्यतन मतलब है और बनाने के लिए अलग से किया जाना चाहिए?
सैम आर।

1
@norbertpy किसी संसाधन पर किसी प्रकार का लेखन कार्य करने से अन्य संसाधनों को अद्यतन किया जा सकता है और एक ही अनुरोध से बनाया जा सकता है। REST के पास कोई समस्या नहीं है। वाक्यांश का मेरा विकल्प इसलिए था क्योंकि कुछ चौखटे एचटीटीपी अनुरोधों को बहु-भाग दस्तावेजों में क्रमबद्ध करके और फिर एक बैच के रूप में क्रमबद्ध HTTP अनुरोध भेजकर थोक संचालन को लागू करते हैं। मुझे लगता है कि दृष्टिकोण संसाधन पहचान बाकी बाधा का उल्लंघन करता है।
डारेल मिलर

19

PUT आईएनजी

PUT /binders/{id}/docs बनाएँ या अद्यतन, और एक बांधने की मशीन के लिए एक दस्तावेज़ से संबंधित हैं

उदाहरण के लिए:

PUT /binders/1/docs HTTP/1.1
{
  "docNumber" : 1
}

PATCH आईएनजी

PATCH /docs यदि वे मौजूद नहीं हैं तो डॉक्स बनाएं और उन्हें बाइंडरों से संबंधित करें

उदाहरण के लिए:

PATCH /docs HTTP/1.1
[
    { "op" : "add", "path" : "/binder/1/docs", "value" : { "doc_number" : 1 } },
    { "op" : "add", "path" : "/binder/8/docs", "value" : { "doc_number" : 8 } },
    { "op" : "add", "path" : "/binder/3/docs", "value" : { "doc_number" : 6 } }
] 

मैं बाद में अतिरिक्त अंतर्दृष्टि शामिल करूंगा, लेकिन इस बीच अगर आप चाहते हैं, तो RFC 5789 , RFC 6902 और विलियम डूरंड की कृपया देखें। एक बेवकूफ की तरह प्रवेश मत करो ब्लॉग प्रविष्टि।


2
कुछ समय क्लाइंट को बल्क ऑपरेशन की आवश्यकता होती है और यह परवाह नहीं करना चाहता कि संसाधन है या नहीं। जैसा कि मैंने सवाल में कहा था, ग्राहक एक गुच्छा भेजना चाहता है docsऔर उन्हें साथ जोड़ना चाहता है binders। यदि वे मौजूद नहीं हैं तो क्लाइंट बाइंडर्स बनाना चाहते हैं और यदि वे करते हैं तो एसोसिएशन बनाते हैं। एक एकल बिल अनुरोध में।
सैम आर।

12

जिस प्रोजेक्ट में मैंने काम किया था, उसमें हमने 'बैच' अनुरोधों को लागू करके इस समस्या को हल किया। हमने एक पथ परिभाषित किया है /batchजहाँ हमने निम्नलिखित प्रारूप में json को स्वीकार किया है:

[  
   {
      path: '/docs',
      method: 'post',
      body: {
         doc_number: 1,
         binder: 1
      }
   },
   {
      path: '/docs',
      method: 'post',
      body: {
         doc_number: 5,
         binder: 8
      }
   },
   {
      path: '/docs',
      method: 'post',
      body: {
         doc_number: 6,
         binder: 3
      }
   },
]

प्रतिक्रिया में स्थिति कोड 207 (बहु-स्थिति) है और इस तरह दिखता है:

[  
   {
      path: '/docs',
      method: 'post',
      body: {
         doc_number: 1,
         binder: 1
      }
      status: 200
   },
   {
      path: '/docs',
      method: 'post',
      body: {
         error: {
            msg: 'A document with doc_number 5 already exists'
            ...
         }
      },
      status: 409
   },
   {
      path: '/docs',
      method: 'post',
      body: {
         doc_number: 6,
         binder: 3
      },
      status: 200
   },
]

आप इस संरचना में हेडर के लिए समर्थन भी जोड़ सकते हैं। हमने कुछ ऐसा लागू किया जो उपयोगी साबित हुआ जो कि बैच में अनुरोधों के बीच उपयोग करने के लिए चर था, जिसका अर्थ है कि हम एक अनुरोध से दूसरे इनपुट के रूप में प्रतिक्रिया का उपयोग कर सकते हैं।

फेसबुक और Google के समान कार्यान्वयन हैं:
https://developers.google.com/gmail/api/guides/batch
https://developers.facebook.com/docs/graph-api/making-multiple-requests

जब आप उसी कॉल के साथ एक संसाधन बनाना या अपडेट करना चाहते हैं तो मैं इस मामले के आधार पर POST या PUT का उपयोग करूंगा। यदि दस्तावेज़ पहले से मौजूद है, तो क्या आप चाहते हैं कि पूरा दस्तावेज़ हो:

  1. आपके द्वारा भेजे गए दस्तावेज़ द्वारा प्रतिस्थापित (अर्थात अनुरोध में अनुपस्थित गुण हटा दिए जाएंगे और पहले से ही विद्यमान हैं)?
  2. आपके द्वारा भेजे गए दस्तावेज़ के साथ विलय (अर्थात अनुरोध में अनुपलब्ध गुण हटाए नहीं जाएंगे और पहले से मौजूद संपत्तियों को अधिलेखित कर दिया जाएगा)?

यदि आप वैकल्पिक 1 से व्यवहार चाहते हैं, तो आपको POST का उपयोग करना चाहिए और यदि आप वैकल्पिक 2 से व्यवहार चाहते हैं, तो आपको PUT का उपयोग करना चाहिए।

http://restcookbook.com/HTTP%20Methods/put-vs-post/

जैसा कि लोगों ने पहले ही सुझाव दिया था कि आप PATCH के लिए भी जा सकते हैं, लेकिन मैं एपीआई की सरलता को बनाए रखना चाहता हूं और अगर जरूरत नहीं है तो अतिरिक्त क्रियाओं का उपयोग करना चाहता हूं।


5
प्रूफ-ऑफ-कॉन्सेप्ट के लिए इस उत्तर के साथ-साथ Google और फेसबुक लिंक भी। लेकिन POST या PUT के बारे में अंत भाग से असहमत हैं। जिन 2 मामलों में यह उत्तर दिया गया है, उनमें पहला पहला PUT होना चाहिए, और दूसरा PATCH होना चाहिए।
रायलू

@RayLuo, क्या आप बता सकते हैं कि हमें POST और PUT के अलावा PATCH की आवश्यकता क्यों है?
डेविड बर्ग

2
क्योंकि यही PATCH का आविष्कार हुआ था। आप इस परिभाषा को पढ़ सकते हैं और देख सकते हैं कि PUT और PATCH आपके 2 बुलेटपॉइंट से कैसे मेल खाते हैं।
रायलू

@DavidBerg, ऐसा लगता है कि Google ने बैच अनुरोधों को संसाधित करने के लिए एक अन्य दृष्टिकोण को प्राथमिकता दी है, अर्थात्, प्रत्येक उप अनुरोध के हेडर और बॉडी को एक मुख्य अनुरोध के संबंधित भाग के लिए, एक सीमा के साथ पसंद किया है --batch_xxxx। क्या Google और फेसबुक के समाधानों के बीच कुछ महत्वपूर्ण अंतर हैं? अतिरिक्त रूप से, "इनपुट के रूप में एक अनुरोध से प्रतिक्रिया का उपयोग करें" के बारे में, यह बहुत दिलचस्प लगता है, क्या आप अधिक विवरण साझा करना चाहेंगे? या किस प्रकार के परिदृश्य का उपयोग किया जाना चाहिए?
यांग
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.