SGB*_*SGB 6 java api rest spring backend
我即将开始在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;
}
Run Code Online (Sandbox Code Playgroud)
要创建一个新地址,我会做这个http请求:
POST http://localhost:8080/addresses
Run Code Online (Sandbox Code Playgroud)
满足以下要求:
{
"line1" : "mandatory Address line 1",
"line2" : "optional Address line 2",
"city" : "mandatory City",
"state" : "cd"
}
Run Code Online (Sandbox Code Playgroud)
假设创建的记录具有id 1
相应的@RestController AddressResource.java将具有以下方法:
@PostMapping(value = "/addresses")
public ResponseEntity<Address> create(@valid Address newAddress) {
addressRepo.save(newAddress);
}
Run Code Online (Sandbox Code Playgroud)
@valid将确保在将数据存储到表中之前实体有效.
现在假设,我从上面的公寓搬到街上的房子.如果我使用PATCH,它就会变成
PATCH http://localhost:8080/addresses/1
Run Code Online (Sandbox Code Playgroud)
请求有效负载:
{
"line1" : "1234 NewAddressDownTheStreet ST",
"line2" : null
}
Run Code Online (Sandbox Code Playgroud)
相应的@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)
}
Run Code Online (Sandbox Code Playgroud)
现在,如果你查询表,我的地址不是吗?
"line1" : "1234 NewAddressDownTheStreet ST",
"line2" : "optional Address line 2", <-- INCORRECT. Should be null.
"city" : "mandatory City",
"state" : "cd"
Run Code Online (Sandbox Code Playgroud)
可以看出,上述更新导致line2的值不正确.这是因为在java中,在实例化类时,Address类中的所有实例变量都被初始化为null(如果它们是基元,则为默认初始值).因此无法区分line2被更改为null与默认值.
问题1)有没有一种标准的解决方法?
另一个缺点是,我不能使用@Valid注释来验证入口点的请求 - 因为它只是部分的.因此,无效数据可能会进入系统.
例如,假设有一个具有以下定义的附加字段:
@Min(0)
@Max(100)
private Integer lengthOfResidencyInYears,
Run Code Online (Sandbox Code Playgroud)
并且用户不小心打了190(当他们真的意味着19年)时,它不会失败.
如果我使用了PUT,客户端需要发送完整的地址对象,而不是PATCH.这样做的好处是我可以使用@Valid来确保地址确实有效
如果有一个前提是在进行任何更新之前必须始终完成GET,为什么不能使用PUT而不是PATCH?我错过了什么吗?
在旁边
我的结论是使用动态类型语言的开发人员是使用PATCH的支持者,因为从静态类型语言行Java或C#中使用它看不出任何好处.它似乎增加了更多的复杂性.
使用PATCH上传现有对象的修改版本几乎总是正是你所概述的原因问题.如果您想使用PATCHJSON,我强烈建议您遵循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" }
]
Run Code Online (Sandbox Code Playgroud)
然后,您将处理此问题,生成一个以当前服务器状态启动并在其中应用更改的新实体对象PATCH.对新实体对象运行验证.如果通过,则将其推送到数据层.如果失败,则返回错误代码.
如果PUT不增加太多开销,那么这是个好主意.幂等是一件好事.权衡是您通过网络推送更多数据.如果您的资源不是很大而且不经常访问,那可能不是什么大问题.如果您的资源很大并且经常被访问,那么这可能会增加很多开销.当然,我们不能告诉你引爆点.
您似乎也已将资源模型完全绑定到数据库模型.对于非平凡的项目,良好的数据库表设计和良好的资源设计通常看起来非常不同.我知道很多框架会让你朝这个方向发展,但是如果你没有认真考虑将它们解耦,你可能会想要.
| 归档时间: |
|
| 查看次数: |
5512 次 |
| 最近记录: |