我有一个具有多个属性的实体,比如“项目”。除了简单的属性,项目可能有一个«状态»列表,其中最后一个是当前的。我有一个Web表单来创建/编辑项目。此项目的所有属性都可以在此表单中更改,用户也可以为项目添加新状态(但不能更改或删除旧状态)。
项目状态是纯粹的复合实体,它们在项目范围之外没有任何独特的含义或标识,并且它们不能直接处理,因此它们显然不值得使用特殊的根REST资源。
根据REST架构,我创建了一个名为/ projects的资源。 POST用于创建新项目,PUT用于更改现有项目。
但是,我不希望客户端将项目与其所有历史状态一起推送,首先是因为此集合太重,其次是因为业务逻辑仅允许添加状态,而不是更改或删除它们,所以无论如何,将项目与其所有状态放在一起并没有任何意义。
设置一个只有新状态的项目也不是一种选择,因为它违反了PUT的幂等性。
我也不喜欢在第二个HTTP请求中发布状态的想法,例如/ project / {id} / status,因为这会从用户的角度打破更新操作的原子性。如果第二个请求在线路上丢失,则项目将与编辑它的用户不一致(属性已更改,但状态保持不变)。创建RESTful“事务”对于更新看似单一的实体这一简单任务来说似乎有点过分(并且也容易出错)。
这种问题在我的工作中非常普遍,并且可能会如此概括:更新复杂的复合实体的REST非常正确和原子的方式是什么?业务逻辑只允许部分更新?
答案 0 :(得分:5)
您需要HTTP PATCH吗?它是表示资源增量更新的动词。
答案 1 :(得分:3)
我认为如果你想进行部分更新(实际上就是你的情况),你应该使用方法PATCH
。这允许更新没有依赖项(状态)的项目或没有项目提示的依赖项。
您可以注意到有一种格式可以描述方法PATCH
中要执行的操作。它被称为JSON补丁(见https://tools.ietf.org/html/rfc6902)。此格式描述了您在请求中要执行的操作:添加元素,更新元素,删除元素,...
我认为如果你想要(例如)更新特定项目的名称,删除一个状态(这也是一个样本,因为我读到你想要禁止这个!)并且添加一个新的一对一原子请求:
PATCH /projects/1
[
{
"op": "replace",
"path": "/name",
"value": "the new name of the project"
},
{
"op": "remove",
"path": "/statuses/1"
},
{
"op": "add",
"path": "/statuses/",
"value": {
"name": "my status",
(...)
}
}
]
请注意,您可以在属性name
中放置所需内容以标识资源状态中的相关元素。因此/statuses/1
可以是数组中的第二个元素,id值为1
的状态或其他内容。
请求的服务器端处理可以是原子的。
我写了一篇关于批量更新的博文:https://templth.wordpress.com/2015/05/14/implementing-bulk-updates-within-restful-services/。我认为“实施批量更新”部分可能与您要查找的内容相对应。
希望它可以帮到你, 亨利