REST API को आंशिक रूप से परिवर्तनीय संसाधनों के लिए PUT अनुरोधों को कैसे संभालना चाहिए?


46

एक REST API का मान लीजिए, एक HTTP के जवाब में GETअनुरोध, एक उप वस्तु में कुछ अतिरिक्त डेटा देता है owner:

{
  id: 'xyz',
  ... some other data ...
  owner: {
    name: 'Jo Bloggs',
    role: 'Programmer'
  }
}

स्पष्ट रूप से, हम नहीं चाहते कि कोई भी PUTवापस आ सके

{
  id: 'xyz',
  ... some other data ...
  owner: {
    name: 'Jo Bloggs',
    role: 'CEO'
  }
}

और क्या वह सफल है। वास्तव में, हम शायद इस मामले में संभावित रूप से सफल होने के लिए एक तरीका भी लागू नहीं करेंगे।

लेकिन यह सवाल केवल उप-ऑब्जेक्ट्स के बारे में नहीं है: क्या, सामान्य तौर पर, डेटा के साथ किया जाना चाहिए जो एक PUT अनुरोध में संशोधित नहीं होना चाहिए?

क्या इसे PUT अनुरोध से गायब होना चाहिए?

क्या इसे चुपचाप त्याग दिया जाना चाहिए?

क्या इसकी जाँच होनी चाहिए, और यदि यह उस विशेषता के पुराने मूल्य से अलग है, तो प्रतिक्रिया में HTTP त्रुटि कोड लौटाएं?

या हमें पूरे JSON भेजने के बजाय RFC 6902 JSON पैच का उपयोग करना चाहिए?


2
ये सभी काम करेंगे। मुझे लगता है कि यह आपकी आवश्यकताओं पर निर्भर करता है।
रॉबर्ट हार्वे

मैं कहूंगा कि कम से कम आश्चर्य का सिद्धांत यह इंगित करेगा कि यह PUT अनुरोध से गायब होना चाहिए। यदि यह संभव नहीं है तो जांच करें और यदि यह अलग है और त्रुटि कोड के साथ वापस आ जाए। साइलेंट त्यागना सबसे खराब है (उपयोगकर्ता भेजने की उम्मीद है कि यह बदल जाएगा और आप उन्हें "200 ठीक" बता रहे हैं)।
मिकीज पीचोटका

2
@MaciejPiechotka के साथ समस्या यह है कि आपको डालने पर समान मॉडल का उपयोग करने के लिए नहीं मिलता है या नहीं मिलता है, आदि, मैं पसंद करूंगा कि एक ही मॉडल का उपयोग किया जाए और वहां साधारण प्राधिकरण नियम हों, ताकि वे एक मान दर्ज करें एक ऐसा क्षेत्र जो उन्हें बदलना नहीं चाहिए, उन्हें वापस 403 निषिद्ध मिल जाता है, और अगर बाद में प्राधिकरण सेटअप करने की अनुमति देता है तो वे 401 अनधिकृत रूप से प्राप्त करने की अनुमति देते हैं यदि वे अधिकृत नहीं हैं
जिमी हॉफ

@ जिमीहॉफ: मॉडल से आपका मतलब डेटा फॉर्मेट से है (जैसा कि एमवीसी रेस्ट फ्रेमवर्क में मॉडल का फिर से उपयोग करना संभव हो सकता है, इसके विकल्प के आधार पर, यदि कोई प्रयोग किया जाता है - ओपी ने कोई उल्लेख नहीं किया है)? अगर मैं फ्रेमवर्क द्वारा बाधा नहीं बन रहा था, तो मैं खोज के साथ जाऊंगा और शुरुआती त्रुटि थोड़ी अधिक खोज / लागू करने में आसान है, तो परिवर्तन के लिए जाँच करना (ठीक है - मुझे फ़ील्ड XYZ को नहीं छूना चाहिए)। किसी भी मामले में त्याग करना सबसे खराब है।
मैकीज पाइचोटका

जवाबों:


46

कोई नियम नहीं है, या तो डब्ल्यू 3 सी कल्पना में या आरईएसटी के अनौपचारिक नियम, जो कहते हैं कि एक PUTही स्कीमा / मॉडल को इसके अनुरूप उपयोग करना चाहिए GET

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

सामान्य तौर पर REST और वेब रोबस्टनेस सिद्धांत से बहुत अधिक बंधे होते हैं : "जो आप करते हैं उसमें रूढ़िवादी बनें [भेजें], जो आप स्वीकार करते हैं उसमें उदार रहें।" यदि आप इसके साथ दार्शनिक रूप से सहमत हैं, तो समाधान स्पष्ट है: PUTअनुरोधों में किसी भी अमान्य डेटा पर ध्यान न दें । यह आपके उदाहरण के अनुसार अपरिवर्तनीय डेटा पर लागू होता है, और वास्तविक बकवास, जैसे अज्ञात क्षेत्र।

PATCHसंभावित रूप से एक और विकल्प है, लेकिन आपको PATCHतब तक लागू नहीं करना चाहिए जब तक कि आप वास्तव में आंशिक अपडेट का समर्थन नहीं करेंगे। PATCHइसका मतलब केवल सामग्री में शामिल विशिष्ट विशेषताओं को अपडेट करना है ; इसका मतलब पूरी इकाई को बदलना नहीं है , लेकिन कुछ विशिष्ट क्षेत्रों को बाहर करना है । जो आप वास्तव में बात कर रहे हैं वह वास्तव में एक आंशिक अद्यतन नहीं है, यह एक पूर्ण अद्यतन, उदासीन और सभी है, यह केवल संसाधन का हिस्सा है, केवल पढ़ने के लिए।

यदि आप इस विकल्प को चुनते हैं, तो एक अच्छी बात यह होगी कि प्रतिक्रिया में वास्तविक अपडेट की गई इकाई के साथ 200 (ओके) को वापस भेजना होगा , ताकि क्लाइंट स्पष्ट रूप से देख सकें कि केवल-पढ़ने के लिए फ़ील्ड अपडेट नहीं किए गए थे।

निश्चित रूप से कुछ लोग हैं जो दूसरे तरीके से सोचते हैं - कि यह एक संसाधन के केवल-पढ़ने के हिस्से को अपडेट करने का प्रयास करने के लिए एक त्रुटि होनी चाहिए। इसके लिए कुछ औचित्य है, मुख्य रूप से इस आधार पर कि आप निश्चित रूप से एक त्रुटि वापस करेंगे यदि संपूर्ण संसाधन केवल-पढ़ने के लिए था और उपयोगकर्ता ने इसे अपडेट करने का प्रयास किया। यह निश्चित रूप से मजबूती के सिद्धांत के खिलाफ जाता है, लेकिन आप इसे अपने एपीआई के उपयोगकर्ताओं के लिए अधिक "स्व-दस्तावेजीकरण" मान सकते हैं।

इसके लिए दो सम्मेलन हैं, दोनों आपके मूल विचारों के अनुरूप हैं, लेकिन मैं उन पर विस्तार करूंगा। पहली सामग्री में केवल पढ़ने के लिए फ़ील्ड्स को प्रदर्शित करने से रोकना है, और यदि वे ऐसा करते हैं तो HTTP 400 (खराब अनुरोध) लौटाएं। यदि किसी अन्य गैर-मान्यताप्राप्त / अनुपयोगी क्षेत्र हैं, तो इस तरह के एपीआई को भी HTTP 400 वापस करना चाहिए। दूसरे को रीड-ओनली फ़ील्ड्स को वर्तमान सामग्री के समान होना चाहिए, और यदि मान मेल नहीं खाते हैं तो 409 (संघर्ष) लौटाएं।

मैं वास्तव में 409 के साथ समानता की जांच को नापसंद करता हूं क्योंकि यह ग्राहक को GETवर्तमान डेटा को पुनः प्राप्त करने के लिए एक आदेश देने के लिए आवश्यक है ताकि वह सक्षम हो PUT। यह सिर्फ अच्छा नहीं है और शायद कहीं न कहीं, किसी के लिए खराब प्रदर्शन का नेतृत्व करने वाला है। मुझे भी वास्तव में इसके लिए 403 (निषिद्ध) पसंद नहीं है क्योंकि इसका तात्पर्य है कि संपूर्ण संसाधन संरक्षित है, न कि इसका केवल एक हिस्सा। इसलिए मेरी राय है, यदि आप दृढ़ता सिद्धांत का पालन करने के बजाय पूरी तरह से मान्य होना चाहिए, तो अपने सभी अनुरोधों को मान्य करें और किसी भी अतिरिक्त या गैर-योग्य क्षेत्र के लिए 400 लौटाएं।

सुनिश्चित करें कि आपका 400/409 / जो कुछ भी विशिष्ट समस्या क्या है और इसे कैसे ठीक करें के बारे में जानकारी शामिल है।

ये दोनों दृष्टिकोण मान्य हैं, लेकिन मैं मजबूती के सिद्धांत को ध्यान में रखते हुए पहले वाले को पसंद करता हूं। यदि आपने कभी बड़े REST API के साथ काम करने का अनुभव किया है, तो आप पिछड़ी संगतता के मूल्य की सराहना करेंगे। यदि आप कभी भी किसी मौजूदा फ़ील्ड को निकालने या उसे केवल पढ़ने के लिए बनाने का निर्णय लेते हैं, तो यह एक पिछड़ा संगत परिवर्तन है यदि सर्वर उन क्षेत्रों को अनदेखा करता है, और पुराने क्लाइंट अभी भी काम करेंगे। हालांकि, अगर आप सामग्री पर सख्त सत्यापन करते हैं, यह है नहीं पिछड़े संगत अब और है, और पुराने ग्राहकों काम करना बंद कर देगा। पूर्व में आम तौर पर एक एपीआई और उसके ग्राहकों के रखरखाव के लिए कम काम होता है।


1
अच्छा जवाब, और उत्थान किया। हालांकि, मुझे यकीन नहीं है कि मैं इससे सहमत हूं: "यदि आप कभी किसी मौजूदा क्षेत्र को हटाने या इसे केवल पढ़ने के लिए तय करते हैं, तो यह एक पिछड़ा संगत परिवर्तन है यदि सर्वर सिर्फ उन क्षेत्रों को अनदेखा करता है, और पुराने ग्राहक अभी भी काम करेंगे। " यदि ग्राहक इस हटाए गए / नव-रीड-ओनली फ़ील्ड पर भरोसा करता है, तो क्या इससे ऐप के समग्र व्यवहार पर कोई प्रभाव नहीं पड़ेगा? खेतों को हटाने के मामले में, मेरा तर्क है कि डेटा को अनदेखा करने के बजाय स्पष्ट रूप से त्रुटि उत्पन्न करना बेहतर होगा; अन्यथा, क्लाइंट को पता नहीं है कि उसका पूर्व-कार्य अद्यतन अब विफल हो रहा है।
rinogo

यह उत्तर गलत है। RFC2616 से 2 कारणों के लिए: 1. (खंड 9.1.2) PUT को स्वतंत्र होना होगा। कई बार लगाएं और यह केवल एक बार लगाने के समान परिणाम देगा। 2. संसाधन प्राप्त करने के लिए एक इकाई मिलनी चाहिए, अगर संसाधन को बदलने के लिए कोई अन्य अनुरोध नहीं किया गया है
ब्रूनोइस

1
क्या होगा यदि आप केवल समानता की जांच करते हैं यदि अनुरोध में अपरिवर्तनीय मूल्य भेजा गया था। मुझे लगता है कि इससे आपको दो दुनिया मिलती है; यदि आप ग्राहकों को एक GET करने के लिए मजबूर नहीं करते हैं, और यदि आप किसी अपरिवर्तनीय के लिए अमान्य मान भेजते हैं, तो आप उन्हें सूचित करते हैं।
अहमद अब्देलघानी

धन्यवाद, अनुभव से आने वाले अंतिम पैराग्राफ में आपने जो गहराई से तुलना की थी, वह वही है जो मैं खोज रहा था।
dhill

9

इदम शक्ति

RFC के बाद, एक PUT को संसाधन के लिए पूर्ण ऑब्जेक्ट देना होगा। इसका मुख्य कारण, यह है कि PUT को बेरोजगार होना चाहिए। इसका अर्थ है एक अनुरोध, जिसे सर्वर पर उसी परिणाम के लिए दोहराया जाना चाहिए।

यदि आप आंशिक अपडेट की अनुमति देते हैं, तो यह अब भी निष्क्रिय-शक्तिशाली नहीं हो सकता। यदि आपके पास दो ग्राहक हैं। ग्राहक A और B, तो निम्न परिदृश्य विकसित हो सकता है:

क्लाइंट A को संसाधन चित्रों से चित्र मिलता है। इसमें छवि का विवरण शामिल है, जो अभी भी मान्य है। क्लाइंट बी एक नई छवि डालता है और तदनुसार विवरण को अपडेट करता है। तस्वीर बदल गई है। क्लाइंट A देखता है, उसे विवरण बदलने की ज़रूरत नहीं है, क्योंकि यह वैसा ही है जैसा वह चाहता है और केवल छवि डालता है।

यह एक विसंगति को जन्म देगा, छवि में गलत मेटाडेटा संलग्न है!

इससे भी अधिक कष्टप्रद यह है कि कोई भी मध्यस्थ अनुरोध दोहरा सकता है। मामले में यह किसी भी तरह PUT विफल रहता है।

PUT का अर्थ बदला नहीं जा सकता (हालाँकि आप इसका दुरुपयोग कर सकते हैं)।

अन्य विकल्प

सौभाग्य से एक और विकल्प है, यह पैट है। PATCH एक ऐसी विधि है जो आपको किसी संरचना को आंशिक रूप से अपडेट करने की अनुमति देती है। आप बस एक आंशिक संरचना भेज सकते हैं। सरल अनुप्रयोगों के लिए, यह ठीक है। यह विधि आइडेंट पोटेंशियल होने की गारंटी नहीं है। ग्राहक को निम्नलिखित फॉर्म में एक अनुरोध भेजना चाहिए:

PATCH /file.txt HTTP/1.1
Host: www.example.com
Content-Type: application/example
If-Match: "e0023aa4e"
Content-Length: 20
{fielda: 1, fieldc: 2}

और सर्वर सफलता का झंडा बुलंद करने के लिए 204 (कोई सामग्री) के साथ वापस जवाब दे सकता है। त्रुटि पर आप संरचना के एक हिस्से को अपडेट नहीं कर सकते। PATCH विधि परमाणु है।

इस पद्धति का नुकसान यह है, कि सभी ब्राउज़र इसका समर्थन नहीं करते हैं, लेकिन REST- सेवा में यह सबसे स्वाभाविक विकल्प है।

उदाहरण पैच अनुरोध: http://tools.ietf.org/html/rfc5789#section-2.1

जौनसँ पाछू

Json विकल्प बहुत व्यापक और एक दिलचस्प विकल्प लगता है। लेकिन तीसरे पक्ष के लिए इसे लागू करना मुश्किल हो सकता है। आपको यह तय करना होगा कि क्या आपका उपयोगकर्ता आधार इसे संभाल सकता है।

यह कुछ हद तक जटिल भी है, क्योंकि आपको एक छोटे दुभाषिया का निर्माण करने की आवश्यकता है जो कमांड को आंशिक संरचना में परिवर्तित करता है, जिसे आप अपने मॉडल को अपडेट करने के लिए उपयोग करने जा रहे हैं। यह व्याख्याकर्ता को यह भी जांचना चाहिए, यदि प्रदान किए गए आदेश समझ में आते हैं। कुछ कमांड एक दूसरे को रद्द करते हैं। (फ़ील्ड लिखें, फ़ील्ड हटाएं)। मुझे लगता है कि आप ग्राहक को उसकी / उसके पक्ष में डिबग समय को सीमित करने के लिए इसे वापस रिपोर्ट करना चाहते हैं।

लेकिन अगर आपके पास समय है, तो यह वास्तव में एक सुंदर समाधान है। आपको अभी भी पाठ्यक्रम के क्षेत्रों को मान्य करना चाहिए। REST मॉडल में रहने के लिए आप इसे PATCH विधि के साथ जोड़ सकते हैं। लेकिन मुझे लगता है कि POST यहां स्वीकार्य होगा।

बुरा जा रहा है

यदि आप PUT विकल्प के साथ जाने का निर्णय लेते हैं, जो कुछ हद तक जोखिम भरा है। फिर आपको कम से कम त्रुटि को नहीं छोड़ना चाहिए। उपयोगकर्ता के पास एक निश्चित प्रत्याशा है (डेटा अपडेट किया जाएगा) और यदि आप इसे तोड़ते हैं, तो आप कुछ डेवलपर्स को अच्छा समय नहीं देने जा रहे हैं।

आप वापस झंडा फहराने के लिए चुन सकते हैं: 409 संघर्ष या 403 निषिद्ध। यह निर्भर करता है कि आप अद्यतन प्रक्रिया को कैसे देखते हैं। यदि आप इसे नियमों (सिस्टम-केंद्रित) के एक सेट के रूप में देखते हैं, तो संघर्ष अच्छा होगा। कुछ इस तरह, इन क्षेत्रों updateable नहीं हैं। (नियमों के विरोध में)। यदि आप इसे प्राधिकरण की समस्या (उपयोगकर्ता-केंद्रित) के रूप में देखते हैं, तो आपको मना किया जाना चाहिए। साथ: आप इन फ़ील्ड्स को बदलने के लिए अधिकृत नहीं हैं।

आपको अभी भी उपयोगकर्ताओं को सभी परिवर्तनीय फ़ील्ड भेजने के लिए बाध्य करना चाहिए।

इसे लागू करने का एक उचित विकल्प इसे उप-संसाधन पर सेट करना है, जो केवल परिवर्तनीय डेटा प्रदान करता है।

निजी राय

व्यक्तिगत रूप से मैं (यदि आपको ब्राउज़रों के साथ काम नहीं करना है) तो साधारण पैटेक मॉडल के लिए जाना होगा और फिर बाद में इसे JSON प्रोसेसर प्रोसेसर के साथ बढ़ा देगा। इस mimetypes पर विभेदित करके किया जा सकता है: चूने के पैच प्रकार:

आवेदन / json-पैच

और json: एप्लीकेशन / json-पैच

इसे दो चरणों में लागू करना आसान बनाता है।


3
अपने आदर्श उदाहरण का कोई मतलब नहीं है। या तो आप विवरण बदलते हैं या आप नहीं करते हैं। किसी भी तरह से, आपको हर बार एक ही परिणाम मिलेगा।
रॉबर्ट हर्वे

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

मुझे पता है कि यह 3 साल पहले था ... लेकिन क्या आप जानते हैं कि RFC में मुझे "PUT को संसाधन के लिए पूरी वस्तु प्रदान करनी होगी" के बारे में अधिक जानकारी मिल सकती है। मैंने इसका उल्लेख कहीं और किया है, लेकिन यह देखना चाहता हूं कि यह कल्पना में कैसे परिभाषित किया गया है।
CSharper

मुझे लगता है मुझे यह मिल गया है? tools.ietf.org/html/rfc5789#page-3
CSharper
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.