簡體   English   中英

在java REST API中,使用PATCH與PUT更新實體

[英]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 6902RFC 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM