在 REST API 中使用 PUT 进行更新时是否应该允许发送完整的结构?
我正在设计一个 REST API,我想知道处理资源更新的推荐方法是什么。更具体地说,我允许通过资源上的 PUT
进行更新,但是我应该在 PUT
请求正文中允许什么?
- 总是资源的完整结构?
- 总是资源结构的子部分(已更改)?
- 两者的结合?
例如,以资源 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?
- Always the complete structure of the resource?
- Always the subpart (that changed) of the structure of the resource?
- 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
是的,始终发送资源的完整表示。否则,您将(根据 PUT 的常见定义和用法)仅用这只狗替换该包。
但是,您可能需要考虑以下事项:
发布到包中。请记住,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:
<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.
PUT 的作用是“替换”。所以,是的,您需要通过 PUT 请求提供完整的表示。
如果您只想更新资源的一部分,您有以下选择:
部分并放置在那里
服务器返回 303 See Other with
指向的 Location 标头
主要资源
在您的情况下,最好将狗作为子资源(包中狗的集合)并以通常的 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:
part and PUT there
the server return 303 See Other with
a Location header pointing to the
main resource
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