用于“重置为默认值”操作的 REST API 设计

mot*_*g88 5 rest api-design http-method

我很惊讶地发现网上很少提到这个困境,这让我想知道我是否完全错过了一些东西。

假设我有一个名为 的单例资源Settings。它是在我的 Web 服务器的 init/install 上创建的,但某些用户可以通过 REST API 修改它,比如说/settings我的 URI。我有一项GET检索设置(作为 JSON)的操作,以及一项PATCH设置一个或多个值的操作。

现在,我想让用户在完成任何调用之前将此资源(或者可能是它的各个属性)重置为默认值 - 默认值是“init 上使用的任何值” PATCH。我似乎找不到任何“最佳实践”方法,但以下是我提出的方法:

  1. DELETE对资源使用操作。毕竟它是幂等的,而且(对我来说)非常清楚。但由于 URI 之后仍然存在DELETE,这意味着资源既没有被删除也没有移动到不可访问的位置,这与 的 RESTful 定义相矛盾DELETE
  2. 将 aPOST用于专用端点,例如/settings/reset- 我真的不喜欢这个,因为它是最明显的非 RESTful,因为动词位于 URI 中
  3. 使用相同的PATCH操作,传递一些“默认”的替代值,例如null值。我遇到的问题是操作的结果与输入不同(我将一个属性设置为null,然后我得到它,它有一个字符串值)
  4. 创建一个单独的默认端点GET,例如/setings/defaults,然后使用 a 中的响应PATCH设置为这些值。这似乎与 REST 没有任何矛盾,但它确实需要 2 个 API 调用才能完成看似简单的操作。

如果上述其中一项认为是最佳实践,或者如果我没有在上面列出其中一项,我很想听听。

编辑:

我的具体项目有一些属性可以简化这个问题,但我最初没有提到它们,因为我的目的是让这个线程作为将来尝试解决相同问题的任何人的参考。我想确保这个讨论足够通用,对其他人有用,但又足够具体,对我也有用。为此,我将附加以下内容。

就我而言,我正在为现有产品设计 API。它有一个面向普通用户的 Web 界面,还有一个 REST(ish)API,旨在满足需要使用所述产品自动执行某些任务的开发人员的需求。在这个过于简单的示例中,我可能将产品部署到一个测试环境,在该环境中我运行各种自动化测试来修改/settings并希望运行一个清理脚本,/settings在完成后重置为正常状态。

该产品还不是 SaaS,并且 API 不是公开的(例如,网络上的任何人都可以自由访问它们)——因此受众以及我可能遇到的潜在“客户”类型相当小——开发人员使用我的产品,该产品部署在他们的私有数据中心或AWS EC2机器中,并且需要用任何语言编写脚本来自动执行某些任务,而不是通过UI来完成。

这意味着缓存等一些技术考虑因素是相关的。人类用户的考虑因素(例如 API 设计在各种资源中的一致性程度以及学习的容易程度)也是相关的。但是“某些第 3 方爬虫能否识别它可以从给定状态执行的下一个操作”并不那么相关(这就是为什么我们不实现 HATEOAS 或OPTIONS根本不实现该方法)

Voi*_*son 1

使用POST就可以了

\n
\n

POST 在 HTTP 中具有许多有用的用途,包括 \xe2\x80\x9c 的一般用途,此操作 \xe2\x80\x99 不值得标准化。\xe2\x80\x9d

\n
\n
POST /settings HTTP/x.y\nContent-Type: text/plain\n\nPlease restore the default settings\n
Run Code Online (Sandbox Code Playgroud)\n

在网络上,您最有可能通过提交表单看到这一点;该表单可能嵌入在 /settings 资源的表示中,或者可能存在于单独的文档中(这取决于缓存等考虑因素)。在该设置中,请求的负载可能会发生变化:

\n
POST /settings HTTP/x.y\nContent-Type: application/x-www-form-urlencoded\n\naction=restoreDefaults\n
Run Code Online (Sandbox Code Playgroud)\n
\n

另一方面:如果该消息的语义值得标准化(即:如果网络上的许多资源应该以相同的方式理解“恢复默认值”),那么您将改为注册新方法令牌的定义,推动其通过标准化流程并促进采用。

\n

因此,我们将在这个定义中指定,例如,该方法的语义是幂等的但不安全,并且还定义我们可能需要的任何新标头。

\n
\n
\n

其中有一点与使用 POST 重置的想法相冲突“REST 方法唯一需要的是为所有资源统一定义它们”。如果我的大部分资源都是典型的 CRUD 集合,那么普遍认为 POST 将创建给定类型的新资源

\n
\n

这里有一个张力你应该注意:

\n
    \n
  • REST 架构风格的参考应用程序万维网。
  • \n
  • HTML 表单支持的唯一不安全方法是 POST
  • \n
  • 网络取得了灾难性的成功
  • \n
\n

支持这一点的想法之一是界面是统一的——浏览器不必知道某个标识符是否引用“集合资源”或“成员资源”或文档或图像或其他内容。缓存和反向代理等中间组件也不会。每个人对自我描述性消息都有相同的理解……甚至是像 POST 这样故意模糊的消息。

\n

如果您想要一条比 POST 具有更具体语义的消息,您可以为其注册一个定义。例如,这正是在PATCH的情况下发生的情况——有人提出,定义一种对有效负载语义附加约束的新方法将允许更丰富、更强大的通用组件。

\n

如果有人足够聪明地坐下来阐述这个案例,那么 CREATE 的语义也可能会发生同样的事情(再次强调:通用组件如何利用语义上的附加约束?)

\n

但在那之前,这些消息应该使用 POST,并且通用组件不应该假设POST 具有创建语义,因为RFC 7231不提供这些额外的约束。

\n