我即將開始在Java中使用新的rest api進行開發。 我的問題是關於使用PATCH - 爲什麼?在java REST API中,使用PATCH與PUT來更新實體
比方說,我們有一個名爲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請求:
POST http://localhost:8080/addresses
有以下要求:
{
"line1" : "mandatory Address line 1",
"line2" : "optional Address line 2",
"city" : "mandatory City",
"state" : "cd"
}
假設創建的記錄有一個ID 1
相應@RestController AddressResource.java將具有此方法:
@PostMapping(value = "/addresses")
public ResponseEntity<Address> create(@valid Address newAddress) {
addressRepo.save(newAddress);
}
@Valid將確保實體是數據存儲到表之前有效。
現在假設我從上面的公寓搬到了街上的房子。如果我使用一個補丁,它成爲
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"
可以看出,上述更新導致line2的值不正確。 這是因爲在java中,當類實例化時,Address類中的所有實例變量都初始化爲null(或者如果它們是基元,則爲初始值)。所以沒有辦法區分將line2從默認值更改爲null。
問題1)有沒有一種標準的方法來解決這個問題?
另一個缺點是,我無法使用@Valid註釋來驗證在入口點的請求 - 怎麼把它僅僅是一個局部的。所以,無效的數據可能會進入系統。
例如,假設有額外的字段定義如下:
@Min(0)
@Max(100)
private Integer lengthOfResidencyInYears,
而且用戶不小心輸入190(當他們真正意味着19歲),就不會失敗。
代替PATCH,如果我使用了PUT,客戶端需要發送完整的地址對象。 這樣做,我可以使用@Valid,以確保該地址的確是有效的
。如果人們的前提是GET時,必須進行做任何更新之前,爲什麼不使用一個PUT優勢通過PATCH? 我錯過了什麼嗎?
除了
我的結論是,使用動態類型語言的開發人員正在使用PATCH,因爲我看不到任何的好處是用它從一個靜態類型語言線Java或C#的支持者。它似乎增加了更多的複雜性。
似乎狀態有效,PATCH請求你的數據庫查詢後,應顯示行:「可選地址行2」,因爲你正在檢查,partialAddress.getLine2()!= NULL。 – kuhajeyan
補丁請求應該包含由客戶端計算的指令,服務器可以使用該指令將某些資源的狀態A轉換爲狀態B,而不僅僅是簡化的部分更新。進一步閱讀:[SO文檔](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/) –
這是一個很好的問題。關於line2中的null,恰恰是因爲您手動映射了字段並檢查非空值以覆蓋。目前,我正在使用[Dozer](http://dozer.sourceforge.net/documentation/usage.html)的項目進行工作,您可以選擇映射空值。無論如何,我們使用POST來添加/創建資源,並使用PUT來修改它們,但使用此映射器,它可以執行部分映射。所以我辯論如果這是首選的方式,或者我應該使用POST(創建),PUT(完全更新),PATCH(部分更新)。 –