通过 REST (PUT/POST) 更新资源

Posted

技术标签:

【中文标题】通过 REST (PUT/POST) 更新资源【英文标题】:Updating a resource through REST (PUT/POST) 【发布时间】:2017-12-26 19:26:46 【问题描述】:

当通过 REST 更新资源时,应该在正文中只包含要更新的值还是整个对象(当前值和要更新的值)?

如果一个用户对象看起来像这样

User (id, name, age, sex)  

如果我的请求如下所示,我想只更新他的姓名和年龄

PUT /users/1

"name":"john","age":18

或者像这样:

PUT /users/1

"name":"john","age":18, "sex":"m"

那在服务器端应该是什么样子?

@RequestMapping(value = "/userId", method = PUT, consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<String> updateUser(@PathVariable final int userId, @RequestBody User u)
    //fetch user by ID 
    user.setName(u.getName())
    user.setAge(u.getAge())
    user.setSex(u.getSex()) //this will be empty?

    return new ResponseEntity<String>(gson.toJson(user), HttpStatus.OK);

或者,我可以找出请求正文中未包含哪些变量并执行类似的操作

if(u.getName()!=null)
     user.setName(u.getName())

if(u.getAge()!=null)
     user.setAge(u.getAge())

if(u.getSex()!=null)
     user.setSex(u.getSex())

是否有正确/错误的方法来实现这一点,或者只是做最简单的事情?

【问题讨论】:

【参考方案1】:

PUT 请求必须是幂等的,并且应该提供它正在替换的实体的完整表示作为其有效负载。 (https://www.rfc-editor.org/rfc/rfc7231#section-4.3.4)

PUT 方法请求目标资源的状态 由表示定义的状态创建或替换 包含在请求消息负载中。

部分 JSON 对象 PUT 请求将是 PATCHContent-Type: application/merge-patch+json (https://www.rfc-editor.org/rfc/rfc7396)

需要考虑的事情。您可能有多个客户端同时更新一个实体,使用 PUT 最终可能会覆盖其他客户端所做的更改。

在这种情况下,您可能需要设置 pre-condition 来检查在请求客户端获取实体、进行更改和提交 PUT/PATCH 请求之间是否更新了对象。例如,前置条件可以是最后更新的时间戳、哈希(Etag)或版本号;或者您可以使用在最终一致的系统中常见的“最后写入获胜”方法。这完全取决于您的系统和情况。

在服务器端,如果您支持部分更新,那么正如您在示例中提供的那样,您将识别请求中包含的一组属性,并仅设置提供的特定属性。

【讨论】:

以上是关于通过 REST (PUT/POST) 更新资源的主要内容,如果未能解决你的问题,请参考以下文章

Rest模式get,put,post,delete含义与区别(转)

REST与SOA两种架构的异同

RESTFul 中PUT POST PATCH的区别

[SOA]REST与SOA两种架构的异同比较

JSONP 对真正 REST 的影响

Rest模式get,put,post,delete含义与区别