[英]In a java REST API, using PATCH vs PUT to update an entity
我即將開始使用Java開發一個新的rest api。 我的問題是關於PATCH的使用 - 為什么?
可以說,我們有一個名為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,它就會變成
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年)時,它不會失敗。
如果我使用了PUT,客戶端需要發送完整的地址對象,而不是PATCH。 這樣做的好處是我可以使用@Valid來確保地址確實有效
如果有一個前提是在進行任何更新之前必須始終完成GET,為什么不能使用PUT而不是PATCH? 我錯過了什么嗎?
在旁邊
我的結論是使用動態類型語言的開發人員是使用PATCH的支持者,因為從靜態類型語言行Java或C#中使用它看不出任何好處。 它似乎增加了更多的復雜性。
使用PATCH
上傳現有對象的修改版本幾乎總是有問題的,正是您所概述的原因。 如果您想將PATCH
與JSON一起使用,我強烈建議您遵循RFC 6902或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
不會增加太多開銷,那么這是一個好主意。 冪等是一件好事。 權衡是您通過網絡推送更多數據。 如果您的資源不是很大而且不經常訪問,那可能不是什么大問題。 如果您的資源很大並且經常被訪問,那么這可能會增加很多開銷。 當然,我們不能告訴你引爆點。
您似乎也已將資源模型完全綁定到數據庫模型。 對於非平凡的項目,良好的數據庫表設計和良好的資源設計通常看起來非常不同。 我知道很多框架會讓你朝這個方向發展,但是如果你沒有認真考慮將它們解耦,你可能會想要。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.