在RESTful资源中更新复合实体

在RESTful资源中更新复合实体,rest,restful-architecture,Rest,Restful Architecture,我有一个具有多个属性的实体,比如«project»。除了简单属性外,项目可能还有一个“状态”列表,其中最后一个是当前状态。我有一个web表单来创建/编辑项目。此表单中可以更改此项目的所有属性,用户也可以为项目添加新状态(但不能更改或删除旧状态) 项目状态是纯粹的复合实体,它们在项目范围之外没有任何独特的含义或标识,并且它们不需要直接处理,因此它们显然不需要特殊的根REST资源 根据REST架构,我创建了一个名为/projects的资源。POST用于创建新项目,PUT用于更改现有项目 但是,我不希

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

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

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

但是,我不希望客户端将项目及其所有历史状态放在一起,首先是因为此集合太重,其次是因为业务逻辑只允许添加状态,而不允许更改或删除状态,因此将项目及其所有状态放在一起没有任何意义

仅使用新状态放置项目也不是一个选项,因为它违反了放置的幂等性

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


这种问题在我的工作中非常普遍,可以概括为这样的问题:对于业务逻辑只允许部分更新的复杂复合实体,什么是REST完全正确且原子化的更新方式?

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


我认为如果你想做部分更新(实际上是你的情况),你应该使用
补丁
的方法。这允许更新没有依赖项(状态)的项目或没有项目提示的依赖项

您可以注意到,有一种格式描述在方法
补丁中要执行的操作。它被称为JSON补丁(请参阅)。此格式描述了您希望在请求中执行的操作:添加元素、更新元素、删除元素

我认为,如果您希望(例如)更新特定项目的名称,删除状态(这也是一个示例,因为我读到您希望禁止这样做!),并在一个原子请求中添加一个新的状态,您可以使用类似的方法:

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为value的status
1
或其他元素

请求的服务器端处理可以是原子的

我写了一篇关于批量更新的博文:。我认为“实现批量更新”一节可能与您所寻找的内容相对应

希望它能帮助你,
Thierry

根据RFC,这似乎是我想要的。但我一直认为补丁方法有点像黑客,不确定它如何适合REST体系结构。REST的大多数描述根本没有提到补丁方法。我知道REST只是一种架构模式,不是一种标准,但是,关于补丁如何适应整个REST架构,是否有任何“规范”的信息来源?REST倡导者根据上下文对资源/实体使用HTTP动词(GET、POST等)。在资源/实体上使用HTTP补丁进行部分更新是尽可能RESTful的。的确,补丁似乎被遗忘/忽略了,但除此之外没有别的了。它有很多原因,但没有一个是因为它的使用可能与RESTful设计冲突。我不知道这个RFC。谢谢不客气!很高兴听到这对你有帮助!