更新RESTful资源中的复合实体

时间:2015-05-25 13:52:45

标签: rest restful-architecture

我有一个具有多个属性的实体,比如“项目”。除了简单的属性,项目可能有一个«状态»列表,其中最后一个是当前的。我有一个Web表单来创建/编辑项目。此项目的所有属性都可以在此表单中更改,用户也可以为项目添加新状态(但不能更改或删除旧状态)。

项目状态是纯粹的复合实体,它们在项目范围之外没有任何独特的含义或标识,并且它们不能直接处理,因此它们显然不值得使用特殊的根REST资源。

根据REST架构,我创建了一个名为/ projects的资源。 POST用于创建新项目,PUT用于更改现有项目。

但是,我不希望客户端将项目与其所有历史状态一起推送,首先是因为此集合太重,其次是因为业务逻辑仅允许添加状态,而不是更改或删除它们,所以无论如何,将项目与其所有状态放在一起并没有任何意义。

设置一个只有新状态的项目也不是一种选择,因为它违反了PUT的幂等性。

我也不喜欢在第二个HTTP请求中发布状态的想法,例如/ project / {id} / status,因为这会从用户的角度打破更新操作的原子性。如果第二个请求在线路上丢失,则项目将与编辑它的用户不一致(属性已更改,但状态保持不变)。创建RESTful“事务”对于更新看似单一的实体这一简单任务来说似乎有点过分(并且也容易出错)。

这种问题在我的工作中非常普遍,并且可能会如此概括:更新复杂的复合实体的REST非常正确和原子的方式是什么?业务逻辑只允许部分更新?

2 个答案:

答案 0 :(得分:5)

您需要HTTP PATCH吗?它是表示资源增量更新的动词。

http://tools.ietf.org/html/rfc5789

答案 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/。我认为“实施批量更新”部分可能与您要查找的内容相对应。

希望它可以帮到你, 亨利