用于更改资源状态的 REST URI 设计



我有一个可以在 URI /resources/{resource_identifier}访问的资源,它有一个我希望可以访问的"状态"属性。我想到了几个选项,哪个是"最好"或"最完整的"?

选项 1 将操作追加到 URI 上,并让客户端POST到这些 URI

/resources/{resource_identifier}/void    
/resources/{resource_identifier}/open    
/resources/{resource_identifier}/close

不过这看起来很笨拙。


选项 2 在 URI 中使用查询参数,并使客户端PATCH这些

参数
/resources/{resource_identifier}?transition=void
/resources/{resource_identifier}?transition=open
/resources/{resource_identifier}?transition=close

选项 3 使用请求的有效负载并让客户端PUT

/resources/{resource_identifier}

有效负载选项:

{ ..., "status" :"void" }
{ ..., "status" :"open" }
{ ..., "status" :"close" }

或者也许完全是别的什么?

第一个选项显然不是 REST; 您在 URI 中有"操作"并且正在使用 POST ,即创建一个新资源,您显然没有尝试这样做。

现在只看 URI 格式。选项二越来越好,但这种性质的查询字符串更多地用于读取数据。没有什么能真正阻止你以这种方式这样做。选项 3 具有最佳 URI 格式,它仅引用要在请求中引用的资源。

如果我们现在考虑请求的方法。在我的书中,这相当简单,我假设状态只是该资源的一个字段,因此如果您只进行部分更新,则正在修补资源,因此PATCH是要使用的方法。如果"状态"是唯一的属性,那么更改状态就是完全更改资源,因此PUT是可以接受的;但我怀疑事实是否真的如此。

就目前而言,第三个选项的 URI 与PATCH的使用相结合可能是最佳选择。

PATCH /resources/{resource_identifier}
{ "status" :"close" }

当然,您也可以将其与通过其自己的 URI 公开特定属性的概念相结合,就好像它们本身就是资源一样。坦率地说,我不喜欢这样,因为它感觉很奇怪,一次只适用于一个属性。不过,如果这是您想要使用的,您可以拥有以下内容:

PUT /resources/{resource_identifier}/status
close

请记住,没有"正确"的REST方法,只有"不错"的方法。这是一种风格,而不是规则集。

我还建议您考虑,一般来说,能够采用多种格式是一个理想的功能。因此,第一个选项往往更容易使用。您可以像示例一样采用 JSON,或者将其交换为 XML <status>close</ status>,或者一个简单的键值对status=closed等。

为什么不将"状态"作为资源。您可以管理它。还假设应该已经创建了一个作为{resource_identifier}资源创建的一部分的"状态",并且已经有一个状态的默认值。

然后,业务逻辑需求只是通过 rest 调用"更新"状态,因此应该使用"PUT"。

更新将状态移动到放置主体

PUT:    /resources/{resource_identifier}/status/
Body: {void | open | close }

在许多情况下,状态更改具有许多业务逻辑。虽然答案是基于"Rest 标准",但我认为有些情况不仅仅是更改状态字段。

例如,如果系统必须取消订单。这不仅仅是更改状态,因为订单具有许多状态,并且每个更改都代表许多逻辑(通知,验证等(。

在使用的情况下:

PATCH /order/1
{ "status" :"cancelled" }

我可以向你保证,逻辑会被客户端和服务器分散,很难维护,也不会有优雅的代码(尤其是在服务器端,它会验证之前的、后续的状态,如果更改一致,它会与更新责任混合在一起(。

我认为使用取消方法并完成其工作更简单。我认为在很多情况下这样做更优雅:

PATCH: /order/1/cancel 
//you could use the body with some cancellation data.

以下链接可以帮助您: https://phauer.com/2015/restful-api-design-best-practices/#keep-business-logic-on-the-server-side

您的第二个选项看起来更好,因为您正在维护 RESTful url 结构,而不是将 RPC 样式的方法附加到其末尾。

为什么不这样做:

PUT /resources/:id数据并随请求一起发送transition=void

它的行为方式与您收到 POST 请求时的行为方式相同,只需从请求正文中获取数据即可。

由于 PUT、GET 和 DELETE 的标准行为大致映射到 CRUD 范式,因此有些人认为资源 API 应该只用于 CRUD 用例。但是,这是一个不正确的评估,因为 POST 可用于执行不能很好地映射到 CRUD 的行为。

在我自己看来,我使用这里普遍同意的两种结构。但是,以下是我如何划清界限。

在对资源属性的更新有副作用的情况下(例如,如果属性的值为 XYZ,则发送邮件(,我让它拥有自己的资源(即端点。 PUT /resources/:id/status (,这将简化控制器级别的事情。否则,我将使用其父级的资源(PATCH /resources/:id/status(

最新更新