我将要开始用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#)中使用它的任何好处。它似乎只增加了更多的复杂性。