REST - 修改部分资源 - PUT 或 POST
我看到很多关于如何使用 REST 只更新部分资源(例如状态指示器)的问题。
选项似乎是:
抱怨 HTTP 没有 PATCH 或 MODIFY 命令。但是,HTTP MODIFY verb for REST? 上接受的答案很好地展示了为什么这不像看起来那么好。
使用带有参数的 POST 并标识一个方法(例如名为“action”的参数)。一些建议是指定具有自定义方法名称的 X-HTTP-Method-Override 标头。这似乎会导致根据您想要做的事情在实现中进行切换的丑陋,并且会接受批评,因为它不是一种特别 RESTful 的 POST 使用方式。事实上,采用这种方法开始感觉像 RPC 类型的接口。
使用 PUT 覆盖资源的子资源,该子资源表示要更新的特定属性。事实上,这实际上是对子资源的覆盖,这似乎符合 PUT 的精神。
在这一点上,我认为#3是最合理的选择。
这是最佳实践还是反模式?还有其他选择吗?
I'm seeing a good bit of hand-waving on the subject of how to update only part of a resource (eg. status indicator) using REST.
The options seem to be:
Complain that HTTP doesn't have a PATCH or MODIFY command. However, the accepted answer on HTTP MODIFY verb for REST? does a good job of showing why that's not as good an idea as it might seem.
Use POST with parameters and identify a method (eg. a parameter named "action"). Some suggestions are to specify an X-HTTP-Method-Override header with a self-defined method name. That seems to lead to the ugliness of switching within the implementation based on what you're trying to do, and to be open to the criticism of not being a particularly RESTful way to use POST. In fact, taking this approach starts to feel like an RPC-type interface.
Use PUT to over-write a sub-resource of the resource which represents the specific attribute(s) to update. In fact, this is effectively an over-write of the sub-resource, which seems in line with the spirit of PUT.
At this point, I see #3 as the most reasonable option.
Is this a best practice or an anti-pattern? Are there other options?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
有两种方法可以查看状态更新。
更新一件事。这是一个 PUT。选项 3
向事物的历史记录中添加额外的日志条目。此日志条目序列中的列表项是当前状态。那是一个帖子。选项 2.
如果您是数据仓库或函数式编程类型,您往往不信任状态更改,并且喜欢将新的历史事实发布到静态、不可变的事物中。这确实需要将事物与事物的历史区分开来。导致两张表。
否则,您不介意通过“更新”来改变事物的状态,并且您对 PUT 感到满意。这不会区分事物及其历史,并将所有内容保留在一张表中。
就我个人而言,我发现我对可变对象和 PUT 越来越不信任(“错误纠正”除外)。 (即使如此,我认为旧的东西可以保留在原处,而新的东西可以参考其之前的版本添加。)
如果有状态更改,我认为应该有状态日志或历史记录,并且应该有是一个向该历史记录添加新条目的 POST。可能有一些优化来反映其适用的对象的“当前”状态,但这只是幕后优化。
There are two ways to view a status update.
Update to a thing. That's a PUT. Option 3
Adding an additional log entry to the history of the thing. The list item in this sequence of log entries is the current status. That's a POST. Option 2.
If you're a data warehousing or functional programming type, you tend to be mistrustful of status changes, and like to POST a new piece of historical fact to a static, immutable thing. This does require distinguishing the thing from the history of the thing; leading to two tables.
Otherwise, you don't mind an "update" to alter the status of a thing and you're happy with a PUT. This does not distinguish between the thing and it's history, and keeps everything in one table.
Personally, I'm finding that I'm less and less trustful of mutable objects and PUT's (except for "error correction"). (And even then, I think the old thing can be left in place and the new thing added with a reference to the previous version of itself.)
If there's a status change, I think there should be a status log or history and there should be a POST to add a new entry to that history. There may be some optimization to reflect the "current" status in the object to which this applies, but that's just behind-the-scenes optimization.
选项 3(PUT 到某个单独的子资源)是您现在最好的选择,并且仅在主资源本身上使用 POST 不一定是“错误” - 尽管您可能不同意这一点,具体取决于您想要的迂腐程度关于它。
坚持使用 3 并使用更细粒度的子资源,如果您确实需要类似 PATCH 的行为 - 请使用 POST。就我个人而言,即使 PATCH 实际上最终成为一个可行的选择,我仍然会使用这种方法。
Option 3 (PUT to some separated sub-resource) is your best bet right now, and it wouldn't necessarily be "wrong" to just use POST on the main resource itself - although you could disagree with that depending on how pedantic you want to be about it.
Stick with 3 and use more granular sub-resources, and if you really do have a need for PATCH-like behavior - use POST. Personally, I will still use this approach even if PATCH does actually end up as a viable option.
HTTP确实有一个 PATCH 命令。它在 RFC 2068 第 19.6.1.1 节中定义,并在 draft-dusseault-http-patch-16< 中进行了更新/a>,目前正在等待作为 RFC 发布。
HTTP does have a PATCH command. It is defined in Section 19.6.1.1 of RFC 2068, and was updated in draft-dusseault-http-patch-16, currently awaiting publication as RFC.
PATCH 适用于patch 或diff 格式。在那之前它根本没有多大用处。
至于使用自定义方法的解决方案2,无论是在请求中还是在标头中,不不不不不,这太糟糕了:)
只有两种有效的方法是放置整个资源,并修改子数据,或 POST 到该资源,或 PUT 到子资源。
这完全取决于资源的粒度以及缓存的预期结果。
PATCH is fine for patch or diff formats. Until then it's not very useful at all.
As for your solution 2 with a custom method, be it in the request or in the headers, no no no no and no, it's awful :)
Only two ways that are valid are either to PUT the whole resource, with the sub data modified, or POST to that resource, or PUT to a sub-resource.
It all depends on the granularity of your resources and the intended consequences on caching.
可以POST &在不可用的情况下模拟 PATCH
在解释这一点之前,可能值得一提的是,使用 POST 进行一般更新没有任何问题(请参阅 这里)特别是:
POST 只有在其他方法非常适合的情况下使用时才会成为问题:例如,检索应该某些资源的表示(GET),完全替换表示(PUT)
实际上,我们应该使用 PATCH 对复杂资源进行小幅更新,但它并没有像我们希望的那样广泛使用。我们可以通过使用附加属性作为 POST 的一部分来模拟 PATCH。
我们的服务需要向第三方产品开放,例如 SAP、Flex、Silverlight、Excel 等。这意味着我们必须使用最低公分母技术 - 有一段时间我们无法使用 PUT,因为只有 GET 和所有客户端技术都支持 POST。
我采用的方法是将“_method=patch”作为 POST 请求的一部分。好处是;
(a) 在服务器端易于处理 - 我们基本上假装 PATCH 可用
(b) 它向第三方表明我们没有违反 REST > 但要解决浏览器的限制。它也与几年前 Rails 社区处理 PUT 的方式一致,因此应该可以被许多人理解
(c) 当 PATCH 变得更广泛可用时,很容易替换
(d) 这是一个 对尴尬问题的务实反应。
It's ok to POST & emulating PATCH where not available
Before explaining this, it's probably worth mentioning that there's nothing wrong with using POST to do general updates (see here) In particular:
POST only becomes an issue when it is used in a situation for which some other method is ideally suited: e.g., retrieval of information that should be a representation of some resource (GET), complete replacement of a representation (PUT)
Really we should be using PATCH to make small updates to complex resources but it isn't as widely available as we'd like. We can emulated PATCH by using an additional attribute as part of a POST.
Our service needs to be open to third-party products such as SAP, Flex, Silverlight, Excel etc. That means that we have to use the lowest common denominator technology - for a while we weren't able to use PUT because only GET and POST were supported across all the client technologies.
The approach that I've gone with is to have a "_method=patch" as part of a POST request. The benefits are;
(a) It's easy to deal with on the server side - we're basically pretending that PATCH is available
(b) It indicates to third-parties that we are not violating REST but working around a limitation with the browser. It's also consistent with how PUT was handled a few years back by the Rails community so should be comprehensible by many
(c) It's easy to replace when PATCH becomes more widely available
(d) It's a pragmatic response to an awkward problem.
答案有点晚了,但我会考虑使用 JSON Patch 对于这样的场景。
其核心是,它需要资源的两个副本(原始副本和修改后的副本),并对其执行比较。 diff 的结果是描述差异的补丁操作数组。
一个例子:
有许多 客户端库 可以完成生成中的困难工作
A bit late with an answer but I would consider using JSON Patch for scenarios like this.
At the core of it, it requires two copies of the resource (the original and the modified), and performs a diff on it. The outcome of the diff is an array of patch operations describing the difference.
An example of this:
There are many client libraries that can do the hard lifting in generat