2016-10-01 23 views
6

अद्यतन करने के लिए पैच बनाम PUT का उपयोग करके मैं जावा में एक नए आराम एपीआई पर विकास शुरू करने जा रहा हूं। मेरा प्रश्न पैच के उपयोग के बारे में है - क्यों?जावा रीस्ट एपीआई में, एक इकाई

POST http://localhost:8080/addresses 
निम्नलिखित अनुरोध के साथ

:

कहना चलें, हम Address.java

public class Address { 

    @Id 
    private Long id 

    @NotNull 
    private String line1; 

    private String line2;  //optional 

    @NotNull 
    private String city; 

    @NotNull 
    private String state; 
} 

नामक एक नया पता बनाने के लिए एक इकाई है, मैं इस http अनुरोध करना होगा

{ 
    "line1" : "mandatory Address line 1", 
    "line2" : "optional Address line 2", 
    "city" : "mandatory City", 
    "state" : "cd" 
} 

मान लें कि बनाए गए रिकॉर्ड में आईडी 1

है

@PostMapping(value = "/addresses") 
public ResponseEntity<Address> create(@valid Address newAddress) { 
    addressRepo.save(newAddress); 
} 

@valid सुनिश्चित करेगा इकाई तालिका में डेटा भंडारण से पहले मान्य है:

इसी @RestController AddressResource.java इस विधि होगा।

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

PATCH http://localhost:8080/addresses/1 

हो जाता है:

{ 
    "line1" : "1234 NewAddressDownTheStreet ST", 
    "line2" : null 
} 

इसी @RestController तरीका होगा:

@PatchMapping(value = "/addresses/{id}") 
public ResponseEntity<Address> patchAddress(@PathVariable Long id, Address partialAddress) 
{ 
    Address dbAddress = addressRepo.findOne(id); 
    if (partialAddress.getLine1() != null) { 
     dbAddress.setLine1(partialAddress.getLine1()); 
    } 
    if (partialAddress.getLine2() != null) { 
     dbAddress.setLine2(partialAddress.getLine2()); 
    } 
    if (partialAddress.getCity() != null) { 
     dbAddress.setCity(partialAddress.getCity()); 
    } 
    if (partialAddress.getState() != null) { 
     dbAddress.setState(partialAddress.getState()); 
    } 

    addressRepo.save(dbAddress) 
} 

अब अगर आप तालिका क्वेरी, जीता ' मेरा पता नहीं है?

"line1" : "1234 NewAddressDownTheStreet ST", 
"line2" : "optional Address line 2",  <-- INCORRECT. Should be null. 
"city" : "mandatory City", 
"state" : "cd" 

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

प्रश्न 1) क्या इस के आसपास काम करने का कोई मानक तरीका है?


एक और नुकसान है कि, मैं प्रवेश बिंदु पर अनुरोध को मान्य करने के @Valid एनोटेशन उपयोग नहीं कर सकते है - coz यह केवल एक आंशिक है। इसलिए, अमान्य डेटा सिस्टम में हो सकता है।

उदाहरण के लिए, कल्पना वहाँ निम्नलिखित परिभाषा के साथ अतिरिक्त क्षेत्र था:

@Min(0) 
@Max(100) 
private Integer lengthOfResidencyInYears, 

और उपयोगकर्ता गलती से 190 लिखा जाता है (जब वे वास्तव में 19 साल के लिए होती है), यह असफल नहीं होता।


PATCH के बजाय, अगर मैं PUT का इस्तेमाल किया था, ग्राहक पूरा पता वस्तु भेजने के लिए की आवश्यकता होगी। यह लाभ है कि मैं @Valid का उपयोग सुनिश्चित करने के लिए कि पता वास्तव में वैध


है एक आधार है कि किसी GET हमेशा किया जाना चाहिए, क्यों होगा डाल एक का उपयोग नहीं अपडेट करने से पहले करता है सकते हैं पैच पर? क्या मुझे कुछ याद आ रही है?

एक तरफ

मेरा निष्कर्ष है कि गतिशील रूप से टाइप किया भाषाओं का उपयोग डेवलपर्स PATCH का उपयोग कर के रूप में मैं किसी भी लाभ से एक स्थिर टाइप किया भाषा लाइन जावा या सी # में प्रयोग करने के लिए नहीं देख सकते हैं के समर्थकों हो रहा है। यह बस अधिक जटिलता जोड़ने लगता है।

+2

स्थिति मान्य लगता है, पैच अनुरोध के बाद आपकी डीबी क्वेरी लाइन दिखानी चाहिए: "वैकल्पिक पता पंक्ति 2", चूंकि आप जांच रहे हैं, partialAddress.getLine2()! = Null। – kuhajeyan

+0

एक पैच-अनुरोध में क्लाइंट द्वारा गणना की गई निर्देश होनी चाहिए, सर्वर कुछ संसाधनों के राज्य ए को राज्य बी में बदलने के लिए उपयोग कर सकता है और न केवल एक सरल आंशिक अद्यतन है। आगे पढ़ने: [एसओ दस्तावेज] (http://stackoverflow.com/documentation/http/3423/http-for-apis/11812/edit-a-resource#t=201610031245323472567) और [अच्छा ब्लॉग पोस्ट] (http://williamdurand.fr/2014/02/14/please-do-not-patch-like-an-idiot/) –

+0

यह एक अच्छा सवाल है। लाइन 2 में शून्य के बारे में ठीक है क्योंकि आप मैन्युअल रूप से फ़ील्ड को मैप करते हैं और आप ओवरराइट करने के लिए गैर शून्य मानों की जांच करते हैं। वर्तमान में मैं एक प्रोजेक्ट पर काम कर रहा हूं जहां हम [डोज़र] (http://dozer.sourceforge.net/documentation/usage.html) का उपयोग करते हैं और आप नल को मैप करना चुन सकते हैं। वैसे भी हम संसाधनों को जोड़ने/बनाने और उन्हें संशोधित करने के लिए POST का उपयोग करते हैं, हालांकि इस मैपर के साथ यह आंशिक मैपिंग कर सकता है। तो अगर मैं पसंदीदा तरीका है या मुझे POST (create), PUT (पूर्ण अपडेट), पैच (आंशिक अपडेट) का उपयोग करना चाहिए तो बहस कर रहा हूं। –

उत्तर

7

किसी मौजूदा ऑब्जेक्ट का एक संशोधित संस्करण अपलोड करने के लिए PATCH का उपयोग करना लगभग आपके द्वारा उल्लिखित कारण के लिए लगभग हमेशा समस्याग्रस्त है। यदि आप JSON के साथ PATCH का उपयोग करना चाहते हैं, तो दृढ़ता से सुझाव देता है कि आप या RFC 7396 का पालन करें। मैं 7396 से बात नहीं करूंगा क्योंकि मैं इससे परिचित नहीं हूं, लेकिन 6902 का पालन करने के लिए आप PATCH संचालन के लिए एक अलग संसाधन परिभाषित करेंगे। उदाहरण आप दे दी है में, यह विचार करेंगे की तरह:

PATCH http://localhost:8080/addresses/1 
[ 
    { "op": "replace", "path": "/line1", "value": "1234 NewAddressDownTheStreet ST" }, 
    { "op": "remove", "path": "/line2" } 
] 

फिर आप इस पर कार्रवाई होगी, एक नई इकाई उद्देश्य यह है कि वर्तमान सर्वर राज्य में शुरू किया और PATCH में परिवर्तन लागू कर रही है। नई इकाई ऑब्जेक्ट पर सत्यापन चलाएं। यदि यह गुजरता है, तो इसे डेटा परत पर दबाएं। यदि यह विफल रहता है, तो एक त्रुटि कोड लौटाएं।

यदि PUT बहुत अधिक ओवरहेड नहीं जोड़ता है, तो यह एक अच्छा विचार है। Idempotency एक अच्छी बात है। ट्रेडऑफ यह है कि आप तार पर अधिक डेटा दबा रहे हैं। यदि आपका संसाधन बड़ा नहीं है और अक्सर उपयोग नहीं किया जाता है, तो शायद यह इतना बड़ा सौदा नहीं है। यदि आपका संसाधन बड़ा है और अक्सर इसका उपयोग किया जाता है, तो यह महत्वपूर्ण ओवरहेड जोड़ना शुरू कर सकता है। बेशक, हम आपको टिपिंग प्वाइंट नहीं बता सकते हैं।

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

+0

स्प्रिंगडाटारेस्ट के साथ मैंने जो उदाहरण देखा है, मुझे लगता है कि यह एक साधारण JSON पेलोड था, लेकिन आपके द्वारा सूचीबद्ध अनुरोध प्रारूप मुझे अधिक समझ में आता है। यदि मैं लेनदेन सीमा के रूप में अपने @ सेवा का उपयोग करता हूं, तो यह पता dbData = getId() और शीर्ष पर परिवर्तन लागू करने के लिए शायद ServiceImpl (और नियंत्रक में नहीं) में होने की आवश्यकता होगी। दिलचस्प जवाब लेकिन अतिरिक्त सुझाव देखने के लिए अब इस प्रश्न को खुला रखेंगे। – SGB

संबंधित मुद्दे