【问题标题】:Proper HTTP method for updating resource without affecting sub-resources in REST用于更新资源而不影响 REST 中的子资源的正确 HTTP 方法
【发布时间】:2011-06-05 22:53:54
【问题描述】:

假设我有两个实体 - 项目团队和员工。每个员工可以是多个团队的一部分,每个团队可以有多个员工作为团队成员。我需要提供 REST API 来操纵团队、员工和他们之间的关系。

我已经确定了 3 个资源 - 团队、员工和成员(团队和员工之间的关联),这是团队的子资源。我选择将成员作为子资源的原因纯粹是基于该资源的生命周期。每当团队被移除时,成员都会被移除,并且他们在团队本身之外没有任何意义。

我公开了以下 API(相关的):

  • POST /teams 使用名称、部门 ID 等创建新的团队记录。
  • POST /teams/{name}/members 在按名称标识的团队和特定员工之间创建关联,因此输入数据包含员工 ID

我还需要提供 API 以在一个请求中更新团队的部门 ID 和其他属性。看起来 PUT 是自然选择,但 PUT 的语义非常清楚 - 我必须替换整个资源,在这种情况下,这意味着也替换所有成员子资源。

当我只想更新团队属性同时保留成员关联时,我应该使用什么方法(或方法)?请记住,我也希望这个请求是幂等的。

【问题讨论】:

    标签: web-services api rest


    【解决方案1】:

    看起来 PUT 是自然选择,但 PUT 的语义非常清楚 - 我 必须替换整个资源,这 在这种情况下意味着更换所有 成员子资源也是如此。

    我以前从未听说过有人建立这种关联。如果在我看来 PUT /Foo ,它完全没有说明 /Foo/bar 。仅仅因为可以通过分层 URI 空间访问资源并不能推断这些资源之间的任何其他关系。

    我听说有人在做与 PUT /Foo/bar 的相反场景,如果服务器知道这会影响 /Foo 的状态,您可以包含指向 /Foo 的 Content-Location 标头以允许智能缓存使/Foo 无效。但是,需要 Content-Location 来显式创建两个资源之间的关系。

    【讨论】:

    • 这点很好。我认为您对我将 URI 视为一组资源的严格树表示是正确的。相反,我应该将它们视为一种识别方式,其中嵌套意味着命名空间的规范。顺便说一句,如果我接受这个假设,“团队”的 GET 响应将如何?在正文中返回成员的 URI 是一件好事,还是我应该只返回团队的属性而忽略成员?也许包括像“/teams/123/members”这样的URI是一种方法?
    • @Oleg 我会在您的团队代表中包含指向/teams/123/members 的链接。
    • 谢谢,我需要再澄清一下,当 PUT 到 /teams/123 时,是否最好在请求正文中省略包含到 /teams/123/members 的链接,否则会混淆客户?
    • @Oleg 不受客户端控制的表示元素,例如超媒体链接,可以从 PUT 请求正文中安全地省略。
    【解决方案2】:

    理想情况下,您应该使用 PATCH 方法,但不确定哪个实现使用它。如果没有,你应该直接 GET -> 本地修改 -> PUT 循环。

    此外,根据您的设计,您可能会认为子资源不是资源本身的一部分。例如,团队资源的内容可能包含指向资源成员列表的链接,例如“/team/{name}/members”,但不会将整个列表作为包含元素。

    【讨论】:

    • 问题是使用 GET->modify->PUT 会使服务器上的逻辑变得非常复杂。它必须确定哪些关联发生了变化并适当地执行后端操作。我宁愿在方法和正文中传达仅更新团队属性的意图。
    • 另一方面,不将成员视为单独的资源可能是个好主意。因此,如果有人想要获取成员列表,则必须发出单独的请求,而“团队”URI 上的 POST/PUT 将始终仅操作团队属性
    【解决方案3】:

    我觉得你是在回答你自己的问题。 PUT 建议创建 资源,POST 用于更新。

    另一种看待这一点的方式是,对资源的每次更改实际上都是在“创建一个新版本”的资源。每次创建、更新和删除都会添加一个具有新属性的新版本,并且该 version 有其自己的唯一标识符。当您PUT 现有资源的新版本时,旧资源仍然存在,以便新资源可以继承它。当该资源的较新版本已经存在时,尝试在旧版本上使用 PUT 新版本将返回重定向而不是成功,一些 GET 请求也会返回(未表明它们实际上正在查找的请求)对于旧版本)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-09-18
      • 1970-01-01
      • 1970-01-01
      • 2017-03-18
      • 2014-04-25
      • 2018-08-16
      • 2012-11-13
      相关资源
      最近更新 更多