我正在看到如何使用REST更新资源的一部分(例如状态指示器)的主题。
选项似乎是:
抱怨HTTP没有PATCH或MODIFY命令。然而,HTTP MODIFY verb for REST?上接受的答案很好地说明了为什么这不像看起来那么好。
将POST与参数一起使用并识别方法(例如,名为“action”的参数)。一些建议是使用自定义方法名称指定X-HTTP-Method-Override标头。这似乎导致了基于你正在尝试做的事情在实现中切换的丑陋,并且批评不是一种特别的REST方式来使用POST。实际上,采用这种方法开始感觉像是一个RPC类型的接口。
使用PUT覆盖资源的子资源,该子资源代表要更新的特定属性。事实上,这实际上是对子资源的重写,这似乎符合PUT的精神。
此时,我认为#3是最合理的选择。
这是最佳做法还是反模式?还有其他选择吗?
答案 0 :(得分:7)
有两种方法可以查看状态更新。
更新一件事。这是一个PUT。备选方案3
在事物的历史记录中添加其他日志条目。此序列日志条目中的列表项是当前状态。这是一个POST。选项2。
如果您是数据仓库或函数式编程类型,您往往会对状态更改不信任,并喜欢将一段新的历史事实POST到静态的,不可变的事物中。这确实需要将事物与事物的历史区分开来;导致两个表。
否则,你不介意改变事物状态的“更新”,你对PUT感到满意。这不区分事物和它的历史,并将所有内容保存在一个表中。
就个人而言,我发现我对可变对象和PUT的信任度越来越低(“错误纠正”除外)。 (即便如此,我认为旧的东西可以留在原地,新的东西也加入了对自己以前版本的引用。)
如果状态发生变化,我认为应该有状态日志或历史记录,并且应该有一个POST来为该历史记录添加新条目。可能会有一些优化来反映适用对象的“当前”状态,但这只是幕后优化。
答案 1 :(得分:5)
选项3(PUT到一些独立的子资源)是你现在最好的选择,并且在主要资源本身上使用POST不一定是“错误的” - 尽管你可能不同意这取决于如何你想成为一个迂腐的人。
坚持3并使用更细粒度的子资源,如果你确实需要类似PATCH的行为 - 请使用POST。就个人而言,即使PATCH确实最终成为一个可行的选择,我仍然会使用这种方法。
答案 2 :(得分:5)
HTTP 具有PATCH命令。它在Section 19.6.1.1 of RFC 2068中定义,并在draft-dusseault-http-patch-16中进行了更新,目前正在等待publication as RFC。
答案 3 :(得分:1)
在解释之前,可能值得一提的是使用POST进行一般更新没有任何问题(参见here)特别是:
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)这是对一个尴尬问题的实用回应。
答案 4 :(得分:1)
PATCH适用于 patch 或 diff 格式。在那之前,它根本不是很有用。
至于你的解决方案2,使用自定义方法,无论是在请求中还是在标题中,不,不,不,不,这很糟糕:)
只有两种有效的方法是PUT整个资源,修改子数据,或POST到该资源,或者PUT到子资源。
这一切都取决于资源的粒度和缓存的预期结果。
答案 5 :(得分:0)
答案有点迟了,但我会考虑在这种情况下使用JSON Patch。
它的核心是需要资源的两个副本(原始副本和修改过的副本),并对其进行区分。 diff的结果是描述差异的 patch操作数组。
一个例子:
[
{ "op": "replace", "path": "/baz", "value": "boo" },
{ "op": "add", "path": "/hello", "value": ["world"] },
{ "op": "remove", "path": "/foo" }
]
有许多client libraries可以在世代上完成艰巨的任务