【问题标题】:How to design REST API for non-CRUD "commands" like activate and deactivate of a resource?如何为非 CRUD“命令”设计 REST API,例如激活和停用资源?
【发布时间】:2014-03-14 17:20:02
【问题描述】:

在我决定提出这个问题之前,我已经搜索了很长时间的答案,但我没有找到任何令人满意的答案。 (例如Examples of the best SOAP/REST/RPC web APIs? And why do you like them? And what's wrong with them?

问题其实很简单。我有一个名为 Account 的对象/资源。我的 REST API 支持所有带有 GET、POST、PUT 和 DELETE 的 CRUD,并具有适当的错误处理、状态代码等。

此外,我还想公开一个 API(“命令”)来激活和停用选定的帐户资源。 即使“isActive”是帐户的属性,我也不想只使用整个帐户的 CRUD 中的更新。

我知道这样的设计很容易违反 REST 原则并进行 RPC 风格设计:

PUT /api/account/:accountId/activate

PUT /api/account/:accountId/deactivate

那么这个用例的最佳解决方案是什么?

我目前的想法是使用像这样的 PUT 和 DELETE 动词(将其视为子资源),正如这里提出的 http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api#restful:

PUT /api/account/:accountId/isActive // 用于激活

DELETE /api/account/:accountId/isActive // 用于停用

你有什么解决方案?

【问题讨论】:

  • 我不认为这是一个“RPC”设计。这是一个基于“消息”的设计。虽然,为什么不在第一个例子中 POST 呢?
  • 使用 POST 作为非幂等方法似乎是标准的。我仍然不确定这种“命令”案例的最佳设计模式是什么。
  • 我发现这个关于“REST-Ful API 设计”youtu.be/oG2rotiGr90 的有趣讨论并使用它定义的规则,例如PUT/PATCH 用于“激活”、“打开”、“安装”等操作。

标签: rest


【解决方案1】:

想出一个你想要修改的特性的名词怎么样 - 在这个例子中是“状态”。这将成为父实体的子资源。因此,对于您的情况,我将按如下方式对 URI 进行建模:

/api/accounts/{accountId}/status

如果“更新”语义是幂等的,那么 PUT 将是最合适的,否则就需要是 POST(例如,如果涉及 nonce 并且被服务无效)。实际的有效负载将包含新状态的描述符。

请注意,我将“帐户”设为复数,因为您可以拥有多个帐户,但状态是单数,因为您的帐户只能有一个状态。

【讨论】:

  • 有趣的方法。然而,通过这种方式,我们将从功能的角度引入一些新的东西(一个新的属性?),从而增加了复杂性。然而,正如我在设计核心领域模型时所说的直觉。
  • 它的旧线程但 PUT“应该”有正文
【解决方案2】:

PATCH 在这种情况下是最合适的方法。更多信息请访问RESTful URL for "Activate"

【讨论】:

  • 这种方法的问题是它隐藏了请求正文中的语义。即使从纯粹设计的角度来看它可能是正确的,我也不会这样做。
【解决方案3】:

POST 方法将创建资源“帐户”。活动可以看作是资源“帐户”的属性之一。因此它应该是一个 PUT 请求。

我会说即使停用也必须是 PUT 请求,因为帐户资源仍然存在。

要激活帐户,您可以在资源上设置属性。那就是:

/api/account/{accountId}?activate=true

停用:

/api/account/{accountId}?activate=false

对帐户的 GET 请求将返回一个带有激活值的 JSON。

DELETE 请求应完全删除帐户资源。

【讨论】:

  • 我很困惑为什么这个答案被否决了。我以前见过这个,它看起来很合适。
  • Neerja,我认为不愿意以这种方式使用查询 (?) 参数,而是将其限制为选择标准/过滤器。
  • 我们应该将查询参数限制为过滤
  • 我认为这不是一个好的答案。首先,PUT 应该“用请求有效负载替换目标资源的所有当前表示”(tools.ietf.org/html/rfc7231#section-4.1),这意味着您应该 PUT 所有有效负载,而不仅仅是单个 status 字段。你最好建议 PATCH。
  • 其次。 “GET、HEAD、OPTIONS 和 TRACE 方法被定义为安全的”(tools.ietf.org/html/rfc7231#section-4.2.1),这意味着用户不必太在意发送它们 - 他应该确信他对 GET 请求的操作不会造成任何伤害。使用?activate=false 参数请求会造成伤害。相比之下,POST、PUT、PATCH、DELETE 并不安全,当用户发送它们时,他必须认为他应对其造成的任何伤害负责。
【解决方案4】:

首先,PUTPOST 相比更合适,因为您正在为已知位置创建资源。而且,我认为,DELETE 没有两难选择。因此,乍一看,您当前的方法似乎优于其他方法。

我以前也是这么想的,直到我实现了自己的 REST api,我希望管理员能够将帐户设置为停用 - 但不删除,只是“禁止” - 状态。当我仔细考虑之后,我决定这样做反之亦然

让我解释一下。我喜欢将activation 资源视为“激活帐户的选项”。因此,如果存在/account/foo/activation 之类的网址,则只能表示该帐户未激活并且用户有权激活它。如果不存在,则说明该帐户已被激活处于禁止状态。

因此,为了激活帐户,唯一合理的做法是尝试DELETE 资源。而且,为了启用激活,管理员必须PUT 激活资源。

现在,我想到的问题是如何区分被禁止的帐户和已激活的帐户。但由于禁令也可以被视为一种资源,您可以创建一个/account/foo/ban 资源集合。为了封禁一个帐户,可能在固定的时间内,您只需 POST 该集合下的一个资源,其中包含封禁的所有详细信息。

【讨论】:

    猜你喜欢
    • 2021-12-09
    • 1970-01-01
    • 1970-01-01
    • 2021-09-02
    • 1970-01-01
    • 1970-01-01
    • 2017-06-04
    • 2019-04-16
    • 1970-01-01
    相关资源
    最近更新 更多