是否应该仅使用POST调用Odata(V4)操作?

时间:2016-10-15 08:25:13

标签: rest asp.net-web-api odata

Odata V4 Spec表示Actions可能有可观察到的副作用,应该使用HTTP POST调用。但我们确实有需要使用仅修改某些状态的操作的场景。

例如:
1.
您可能希望将标识为id的文档的状态标记为已锁定  端点 - ... / Documents({id})/ lock()。
 由于我在这里做了部分更新,在我看来PATCH更合适。

你可能想提供两种删除文件的方法
 a)只需隐藏终点 - ..... / Documents({id})
这是HTTP DELETE(无争议)

 b)永久删除终点 - ..... / Documents({id})/ permanentDelete()
这作为ODATA操作。
在我看来,HTTP删除更合适这里没有HTTP POST。

从Odata的角度来看,推荐的方法是什么?非常感谢任何帮助。

以下是SPEC的信息。

SPEC 11.5.4行动

操作是由OData服务公开的操作,在调用时可能会产生副作用。动作可以返回数据,但不能进一步用其他路径段组成。 11.5.4.1调用操作

要调用绑定到资源的操作,客户端会向操作URL发出 POST 请求。可以从先前返回的实体表示获得动作URL,或者通过将名称空间或别名限定的动作名称附加到URL来标识动作URL,该URL标识类型与绑定参数的类型相同或源自的绑定参数的类型。那个行动。绑定参数的值是在附加操作名称之前由URL标识的资源的值,并且根据特定格式在请求主体中传递任何非绑定参数值。

提前致谢
--ksp

2 个答案:

答案 0 :(得分:1)

从OData的角度来看,你总是要用POST来调用一个动作,而其他任何动词都不行。

你的两个例子都是我个人认为不适合某个动作的东西,因为已经有办法用OData做这些事情,并且他们使用你提到的动词。更新属性支持一个DELETE支持PATCH和删除对象。你提到你有两种不同类型的删除操作,这更难,但你可以使用自定义标题来区分它们。

操作往往不适合普通的CRUD操作,因此并不总是清楚应该使用哪个HTTP谓词。

在您的示例中,感觉确实想要使用DELETE和PATCH。然而,问题的出现是因为我们需要遵循一个标准,请记住,OData操作都可以通过元数据发现,因此客户可以使用它而不知道实际操作的内容,在这种情况下,我们需要有定义的东西。既然我们知道动作会以某种方式影响服务器,对我而言,POST似乎是对所有操作都一致的最不好选择。

答案 1 :(得分:0)

最后,作为作者,您可以命令自己的API。正如我们不应在C#类设计中使用会在其他属性中引起副作用的属性一样,这并不意味着我们做不到,而且这很普遍。

从OData的角度来看,PATCH类似于使用属性访问器,而 actions POST用于访问方法。

PATCHPOST之间做出决定以影响更改,因此在使用属性 mutators (使它们可写)或强制调用者设置其属性之间,存在相同的设计决策。通过相关的方法值。

  1. 您可能希望将ID标识的文档的状态标记为已锁定 端点-... / Documents({id})/ lock()。 由于我在这里进行了部分更新,因此我认为PATCH更合适。

如果您的资源具有名为Locked属性,而您当前的lock() Action 仅将Locked属性设置为{ {1}},那么您可以可以简单地使用true来更新该PATCH字段。

一些专门用于 lock 进程的 Action 的常见原因:

  1. 您希望在调用Locked时执行特定的逻辑,并且希望在其自己的方法中维护此逻辑,而不是在修补程序处理程序中使用复杂的条件逻辑。
  2. 当资源被锁定时,您不希望反向逻辑lock()供所有人使用 ,大概只是锁定该资源的用户可以释放锁或其他需要满足的条件。
    • 与第一点一样,这种逻辑通常更容易以自己的方法维护,因此 Action
  3. 您要使用安全属性将对unlock()的访问限制为某些安全组,但是您希望所有用户都具有对lock()状态字段的读取访问权限。
  4. 当资源被锁定时,还将设置其他字段,例如Locked,甚至还有LockedBy

虽然所有这些逻辑 都可以在控制器的单个DateLocked端点逻辑中进行管理,但我无法强调这将如何使您的解决方案随着时间的推移难以管理。资源的复杂性会增加。

更重要的是::已记录并接受的约定是PATCH具有副作用,因此无需执行{{ PATCH之后的1}},因为服务器上已接受客户端的相同更改。相反,由于GET MAY 具有副作用,因此,如果来自{{的响应,则客户可以期望执行PATCH以获取所有相关更改,这是合理的。 1}}不包含更新的资源。

POSTGET的情况下,现在事情变得个人化/自以为是了…… 按照惯例,对POST的期望是双重的:

  1. 删除后,资源不应再出现在Delete的集合查询结果中
  2. 删除后,资源不应再通过PermanentlyDelete出现在项目请求中

从服务器的角度来看,如果我的资源具有 soft 删除,则只需设置一个标志,而 permanent 删除则从基础存储中删除记录,那么按照惯例,我将对{em> soft 删除使用称为DELETE的{​​{1}},而对 permanent 删除应该使用GET http动词。

  • 对此的一般推理与关于GET的讨论相同。

但是,如果 soft permanent 删除的目的是拦截客户端的标准删除工作流程,则永久删除概念将被隐藏或以某种方式抽象化而不是通常的工作流程的一部分(用户必须去其他地方,例如回收站以查看已删除的记录并还原或永久删除),在这种情况下,请使用HTTP动词{{ 1}}进行软删除,并进行特定的,可能是集合绑定的 Action 来接受永久删除的请求

  • 根据您实施过滤的方式,此操作可能必须是未绑定的或绑定到集合的,如果我们删除了记录“ xyz”,例如Action返回Delete(),那么我们将无法真的希望DELETE执行...