REST - PUT 方法是否必须删除省略的可选字段?

REST - Does the PUT method have to remove an optional field when it is omitted?

我有一个资源 Car,其中有一些必填字段和另一个可选字段。

Car 是根据以下请求创建的:

POST /cars
{
  plate: "XYZ-A2C4",
  color: "blue,
  owner: "John" //OPTIONAL
}

REST 客户端想要更新这辆车的所有必需信息:

PUT /cars/:id
{
  plate: "ABC-1234",
  color: "black"
}

owner 可选字段发生了什么变化?


我知道服务器可以提供 PATCH 方法,但有时无法更新单个字段,因为新状态可能变得无效(没有最低要求的有效负载来强制执行相关字段值)。此外,在使用 PATCH 的某些情况下,使用 null 操作数组、删除字段或设置它可能会很棘手,因为它可以使用两种不同的模式来完成; JSON 合并补丁有限,JSON 补丁有点奇怪


是否可以使用必填字段执行 PUT 并且服务器在省略时保留旧的可选值?

严格来说,PUT 应该用提供的实体替换被标识的资源。在您的示例中,这意味着 car 将在没有可选字段的情况下被替换,除非 PUT 请求中也提供了可选字段。

严格遵守 REST 或面向资源的架构的 API 数量非常少,所以我个人会尽量不涉及这种详细程度,而只是记录您的 api 和行为您的用户可以期待。

如果你真的想对它狂热,我认为你在 PATCH 的轨道上是正确的,或者你可以确定一个子资源:

PUT /cars/:id/plate
"ABC-1234"

PUT /cars/:id/color
"black

或者也许:

PUT /cars/:id/description
{
  plate: "ABC-1234",
  color: "black"
}

如果您想照章办事(section 4.3.4 of RFC 7231),那么,在您的情况下,PUT 请求应该替换整个 Car资源:

The PUT method requests that the state of the target resource be created or replaced with the state defined by the representation enclosed in the request message payload. A successful PUT of a given representation would suggest that a subsequent GET on that same target resource will result in an equivalent representation being sent in a 200 (OK) response.

因此,根据书本,您不应使用 PUT 进行部分更新,而应使用 PATCH。

然而,在实践中,真正由您来决定如何这究竟适用于您的服务,更重要的是,文档它.

以下是一些知名 API 如何允许部分更新的真实示例:

  • Ghost API不支持部分资源更新,任何更新都需要完整资源的PUT请求
  • Rossum API 支持 PATCH 进行部分资源更新,但他们的文档明确指出仅支持顶级属性
  • GitHub 允许 PATCH 和 POST 部分数据更新请求
  • Firebase 允许 PATCH 请求,但也 POST 带有 X-HTTP-Method-Override header

您说得对,有时候,如果按原样处理,PATCH 方法可能会导致资源无效。然而,作为副作用,没有什么能阻止服务器确保正确的数据状态。因此,在每次通话期间,您可以让服务器:

  • 在持久化之前验证资源的正确状态
  • 拒绝(带有 400 Bad Request 错误)任何会导致不正确状态的请求
  • 成功时用资源响应(可能会产生副作用)

www-tag 邮件列表档案包含来自 Roy Fielding in 2002 的有趣观察:

HTTP does not attempt to require the results of a GET to be safe. What it does is require that the semantics of the operation be safe, and therefore it is a fault of the implementation, not the interface or the user of that interface, if anything happens as a result that causes loss of property (money, BTW, is considered property for the sake of this definition).

HTTP PUT 的规范应该以同样的方式理解;规范告诉我们消息 的意思,但没有告诉我们如何去做。

The PUT method requests that the state of the target resource be created or replaced with the state defined by the representation enclosed in the request message payload.

PUT 语义基本上是“远程创作”;该请求告诉服务器使其资源副本看起来像客户端副本。

因此,当您在请求中提供的表示中留下一个“可选”元素时,您是在告诉服务器从它自己的表示中也删除该可选元素。

客户有责任创建描述其实际需求的消息。因此,如果您的客户希望可选字段在您的请求后保持不变,则需要将它们包含在您包含在请求正文中的表示中。

服务器应按所述解释 PUT 请求;但它没有限制它对这种事情的处理方式(根据上面菲尔丁的观察:当事情出错时,责备指向哪个方向?)

HTTP does not define exactly how a PUT method affects the state of an origin server beyond what can be expressed by the intent of the user agent request and the semantics of the origin server response.

What happen to the owner optional field?

因此在您的具体示例中,请求明确表示“不包含所有者元素”。但是服务器可以忽略它;它只需要小心地设计它的响应,不要暗示所提供的表示是未更改的。