在 REST API 中使用 PUT 进行更新时是否应该允许发送完整的结构?

发布于 2024-08-30 13:48:55 字数 1611 浏览 9 评论 0原文

我正在设计一个 REST API,我想知道处理资源更新的推荐方法是什么。更具体地说,我允许通过资源上的 PUT 进行更新,但是我应该在 PUT 请求正文中允许什么?

  1. 总是资源的完整结构?
  2. 总是资源结构的子部分(已更改)?
  3. 两者的结合?

例如,以资源 http://example.org/api/v1/dogs/packs/p1 为例。 此资源上的 GET 将给出以下内容:

Request:
GET http://example.org/api/v1/dogs/packs/p1
Accept: application/xml

Response:
<pack>
  <owner>David</owner>
  <dogs>
    <dog>
      <name>Woofer</name>
      <breed>Basset Hound</breed>
    </dog>
    <dog>
      <name>Mr. Bones</name>
      <breed>Basset Hound</breed>
    </dog>
  </dogs>
</pack>

假设我想向包中添加一只狗(嗅探巴吉度猎犬),我会支持以下其中之一:

Request:
PUT http://example.org/api/v1/dogs/packs/p1
<dog>
  <name>Sniffers</name>
  <breed>Basset Hound</breed>
</dog>

Response:
HTTP/1.1 200 OK

还是

Request:
PUT http://example.org/api/v1/dogs/packs/p1
<pack>
  <owner>David</owner>
  <dogs>
    <dog>
      <name>Woofer</name>
      <breed>Basset Hound</breed>
    </dog>
    <dog>
      <name>Mr. Bones</name>
      <breed>Basset Hound</breed>
    </dog>
    <dog>
      <name>Sniffers</name>
      <breed>Basset Hound</breed>
    </dog>
  </dogs>
</pack>

Response:
HTTP/1.1 200 OK

两者都支持?如果建议通过结构的子部分支持更新,我将如何处理删除(例如当狗死亡时)?通过查询参数?

I am designing a REST API and I wonder what the recommended way to handle updates to resources would be. More specifically, I would allow updates through a PUT on the resource, but what should I allow in the body of the PUT request?

  1. Always the complete structure of the resource?
  2. Always the subpart (that changed) of the structure of the resource?
  3. A combination of both?

For example, take the resource http://example.org/api/v1/dogs/packs/p1.
A GET on this resource would give the following:

Request:
GET http://example.org/api/v1/dogs/packs/p1
Accept: application/xml

Response:
<pack>
  <owner>David</owner>
  <dogs>
    <dog>
      <name>Woofer</name>
      <breed>Basset Hound</breed>
    </dog>
    <dog>
      <name>Mr. Bones</name>
      <breed>Basset Hound</breed>
    </dog>
  </dogs>
</pack>

Suppose I want to add a dog (Sniffers the Basset Hound) to the pack, would I support either:

Request:
PUT http://example.org/api/v1/dogs/packs/p1
<dog>
  <name>Sniffers</name>
  <breed>Basset Hound</breed>
</dog>

Response:
HTTP/1.1 200 OK

or

Request:
PUT http://example.org/api/v1/dogs/packs/p1
<pack>
  <owner>David</owner>
  <dogs>
    <dog>
      <name>Woofer</name>
      <breed>Basset Hound</breed>
    </dog>
    <dog>
      <name>Mr. Bones</name>
      <breed>Basset Hound</breed>
    </dog>
    <dog>
      <name>Sniffers</name>
      <breed>Basset Hound</breed>
    </dog>
  </dogs>
</pack>

Response:
HTTP/1.1 200 OK

or both? If supporting updates through subsections of the structure is recommended, how would I handle deletes (such as when a dog dies)? Through query parameters?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

痴情 2024-09-06 13:48:55

是的,始终发送资源的完整表示。否则,您将(根据 PUT 的常见定义和用法)仅用这只狗替换该包。

但是,您可能需要考虑以下事项:

  • 使用 XML 命名空间或其他版本控制方法(例如?version=2) 在 URL 路径之外
  • 将要添加的狗 POST 到 /dogs/packs/ p1。根据定义,POST 创建一个从属资源,以便将狗添加到资源包中。
  • 稍微刷新一下你的网址。在我看来,你确实想要 /dogs/1234、/dogs/1235 等等,然后是 /packs/p1、/packs/p2。然后您也可以简单地将 发布到包中。

请记住,REST 要求您正确识别资源。包实际上并不是狗的从属资源,每只狗都应该有某种唯一的标识符。然后,当访问 /packs/p1/1234 时,您可能希望重定向到 /dogs/1234。或者,您也可以不使该 URL 可用,尽管接受将从属资源发布到相应包。

我想得越多,POST 方法就越有意义。也许您甚至可以为所有狗提供一个 /packs/p1/dogs/ 资源,与包分开。然后,您可以将所有者信息等内容放入 /packs/p1,通过 /packs/p1/dogs/ 获取所有狗的列表(其中应包含每只狗的 URL 列表) pack,例如 /packs/p1/dogs/1234,请参阅 HATEOAS),添加一条新狗到通过 POST 到 /packs/p1/dogs/ 来删除狗,并通过 DELETE /packs/p1/dogs/1235 来删除狗。每只狗都可以是完整的表示,甚至可以重定向到 /dogs/1234 等,也可以是该包上下文中狗的不同表示,但同样带有指向“完整”狗的链接。取决于您想要如何表示包中的单只狗,这当然也会影响您实际发布到 /packs/p1/dogs/ 的内容。 Full Dog 感觉不对,实际上应该只是一个 ID,如我上面所示,也许还有与包的关系有关的附加数据。

Yes, always send the complete representation of the resource. Otherwise, you would (according to common definition and usage of PUT) replace the pack with just this one dog.

However, you might want to consider the following:

  • use XML namespaces or other means of versioning (e.g. ?version=2) outside of the URL path
  • POST the dog you want to add to /dogs/packs/p1. POST by definition creates a subordinate resource, so that would add the dog to the pack.
  • Refurbish your URLs a bit. It seems to me you really want to have /dogs/1234, /dogs/1235 and so forth, and then /packs/p1, /packs/p2. Then you could also simply POST <dog id="1"> to the pack, too.

Keep in mind that REST requires you to properly identify resources. packs are not really a subordinate resource to the dogs, and each dog should have some sort of unique identifier. Then, when accessing /packs/p1/1234, you would probably want to redirect to /dogs/1234. Or, alternatively, you would simply not make that URL available, despite accepting POSTing of subordinate resources to the respective pack.

The more I think about it, the more sense the POST approach makes. Maybe you could even have a /packs/p1/dogs/ resource for all the dogs, separate from the pack. Then, you can PUT stuff like owner information etc to /packs/p1, GET a list of all dogs via /packs/p1/dogs/ (which should contain a list of URLs to each dog in the pack, e.g. /packs/p1/dogs/1234, see HATEOAS), add a new dog to the pack by POSTing to /packs/p1/dogs/, and remove a dog by DELETEing /packs/p1/dogs/1235. Each dog could either be the full representation, maybe even with a redirect to /dogs/1234 etc, or a different representation of the dog in the context of this pack, but again with a link to the "full" dog. Depends on how you want to represent a single dog in a pack, and that will of course also influence what you actually POST to /packs/p1/dogs/. Full dog feels wrong, should really be just an ID as I showed above, maybe with additional data pertaining to the relationship with the pack.

套路撩心 2024-09-06 13:48:55

PUT 的作用是“替换”。所以,是的,您需要通过 PUT 请求提供完整的表示。

如果您只想更新资源的一部分,您有以下选择:

  • 定义代表资源的资源
    部分并放置在那里
  • 使用 POST 到子资源并有
    服务器返回 303 See Other with
    指向的 Location 标头
    主要资源
  • 使用 PATCH

在您的情况下,最好将狗作为子资源(包中狗的集合)并以通常的 POST-as-append 方式 POST 到该子资源

PUT's effect is 'replace'. So, yes, you need to supply the complete representation with a PUT request.

If you want to do update only parts of the resource you have the following choices:

  • Define a resource that represents the
    part and PUT there
  • Use POST to a sub resource and have
    the server return 303 See Other with
    a Location header pointing to the
    main resource
  • Use PATCH

In your case, it would likely be best to make the dogs a sub resource (the collection of dogs of the pack) and POST to that in the usual POST-as-append manner

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文