非 CRUD 操作上的 REST

REST on non-CRUD operations

我有一个名为“订阅”的资源

我需要更新订阅的发送日期。当请求发送到我的端点时,我的服务器将调用第三方系统来更新传递的订阅。

“订阅”有其他类型的更新。例如,您可以更改订阅的频率。这个操作还涉及到从我的服务器调用第三方系统。

要成为真正的“RESTful”,我必须强制这些不同类型的更新共享一个端点吗?

PATCH subscriptions/:id

假设我可以在端点后面使用我的控制器来根据查询字符串触发不同的功能...但是如果我需要添加第三个或第四个“更新”类型的操作怎么办?他们都应该 运行 通过这条 PATCH 路线吗?

To be truly “RESTful,” must I force these different types of updates to share an endpoint?

不 - 但你会经常想要。

考虑如何在 Web 上支持此功能:您可能有许多不同的 HTML 表单,每个表单接受一组略有不同的用户输入。提交表单时,浏览器将使用输入控件和表单元数据构造一个 HTTP (POST) 请求。请求的目标 URI 从表单操作中复制。

所以您的问题类似于:我们是否应该对所有不同的表单使用相同的操作?

答案是肯定的,如果您希望通用 HTTP 应用程序了解预期哪个资源会更改以响应消息。您可能想要的原因之一是 cache invalidation;使用正确的目标 URI 允许所有缓存了解哪些以前缓存的响应不应该被重用。

那个选择是免费的吗?否 - 它会给您的访问日志增加一些歧义,并且将请求路由到代码中的适当处理程序需要更多的工作。


尝试将 PATCH 与不同的目标 URI 一起使用有点奇怪,这表明您可能正在尝试将 PATCH 扩展到标准约束之外。

PATCH(和 PUT)具有远程创作语义;他们的意思是“让你的目标资源副本看起来像我的副本”。这些是我们在尝试修复网页上的拼写错误时会使用的方法。

尝试通过向 不同 资源发送远程创作请求来更改一种资源的表示,这使得通用 HTTP 应用程序组件更难增加价值。您在线条之外着色,这意味着如果出现任何问题,您将承担责任,因为您以非标准方式使用标准化消息。


也就是说,许多 不同的资源呈现同一域实体的表示是合理的。与其将您对某个用户的所有了解都放在一个网页中,不如将其分散到多个链接在一起的网页中。

例如,您可能有一个用于发票的网页,然后是另一个用于运输信息的网页,以及另一个用于帐单信息的网页。您现在拥有一个关注点分离更清晰的资源模型,并且可以将 PUT/PATCH 的标准化含义与该资源模型结合起来以进一步实现您的业务目标。

We can create as many resources as we need (in the web level; at the REST level) to get a job done. -- Webber, 2011


So, in your example, would I do one endpoint like this user/:id/invoice/:id and then another like this user/:id/billing/:id

Resources, not endpoints.

GET /invoice/12345
GET /invoice/12345/shipping-address
GET /invoice/12345/billing-address

GET /invoice/12345
GET /shipping-address/12345
GET /billing-address/12345

您用于资源标识符的拼写约定实际上并不重要。

因此,如果将所有这些都放入一个包含用户和发票的层次结构中会让您的生活更轻松,那也很好。