RESTful API 设计和 CQRS

RESTful API Design and CQRS

我在想如何让 RESTFul API 更能暴露意图。我在各种博客上看到的一个常见模式是传统的 REST API 结果

禁止玩家 -> POST /players.

但是我要换一个更能显示意图的界面,我可以用

禁止玩家 -> POST /players/{ playerid }/banPlayer

第二个我觉得比较暴露意图。

我从团队中得到的普遍反对意见是第二个不符合 start REST 风格。

目前我还不能离开 RESTful API。

我想听听您对此的看法。

根据 REST API 方法,您需要在 URI 中使用您的实体,因此,由于 banPlayer 不是实体,您不能使用它。 我建议使用 PUT 方法更新您的记录。 Here 您可以阅读有关规则的更多信息。实际上,关于 URIs 的第一部分只是关于您的情况。

对于 Restful API 设计,围绕如何将 actions 应用于资源有两种思想流派。

  1. 您在 URI 中描述了要对资源采取的操作:

    请求 URI:
    POST /players/{id}/ban

    注意:只需使用 ban - 我们已经知道资源是一个播放器,它在基本 Uri 中。

  2. 您可以在请求正文中包含操作:

    请求 URI:
    POST /players/{id}

    请求正文:
    { 'action': 'ban' }

您可以选择任何一种方式 - 无论您喜欢哪种方式,都有很多关于这两种方式的讨论,但最终两者都是正确的。

注:

我在这里的假设是禁止玩家不仅仅是更新它的一部分,而是与玩家相关的系统操作(或状态转换)。否则,如果它只是对播放器资源的更新,您应该根据需要使用 PATCH 或 PUT 进行处理。

一些供参考的讨论:

如果你用谷歌搜索还有更多...

The common objection I get from the team is that the second one does not comply with start REST style.

简单的答案是:API 中的一致性具有价值,无论是否为 REST。所以 "that's not how we do it here" 将胜过 "but REST says"。

API 中 URI 的拼写很像代码中方法名称的拼写。不同的风格有很多不同的论据,但 "local convention" 本身就是一个强有力的论据。

就是说 -- REST 不关心您使用什么拼写作为标识符。

这就是Fielding had to say in 2008

A REST API should spend almost all of its descriptive effort in defining the media type(s) used for representing resources and driving application state, or in defining extended relation names and/or hypertext-enabled mark-up for existing standard media types. Any effort spent describing what methods to use on what URIs of interest should be entirely defined within the scope of the processing rules for a media type (and, in most cases, already defined by existing media types). [Failure here implies that out-of-band information is driving interaction instead of hypertext.]

带内将在资源表示中包含 URI——将其放入 HTML 文档中的表单描述中。带外正在记录 URI,并期望人们用它做正确的事。

注意:人类可读的 URI 或记录应使用的 URI 没有任何问题。但是请注意,您可以 post 向 Whosebug 提问,即使编写您的浏览器的人没有阅读 stack overflow's API documentation —— 这就是 REST。

长话短说:不应该强制公开意图,但如果您想添加一些 DDD 关于这个 API 的外观就像那样,没有什么能阻止你那样做

根据 HATEOAS constraint of a RESTful web API (this constraint is an essential part of the "uniform interface" feature of REST, as defined in Roy Fielding's doctoral dissertation), the software clients of your API should not care about the URLs. Every possible&permitted action should be included in the response, with the corresponding link relation 和 URI。通过这种方式,您只需对 link 关系进行硬编码。

然而,此约束不会阻止您为试图了解整体架构的 人类 客户端提供更多 API 意图。我建议你选择这条路,因为人类用户至少和他们编写的软件一样重要。

Roy Fielding 在 his blog post 上写了这篇文章。

由于您要求的 RESTful 方法不是最好的方法,所以这是我的想法。

您的 RESTful URI 选项包括:

  • /players
  • /players/{ playerid }/banPlayer
  • /player-banning
  • /entities?action=ban_player&method=PUT
  • /banana
  • 除此之外,REST 不会规定您的 URI 应该是什么样子

RESTful 方式是纯粹通过超文本公开下一个可用状态的知识。要实现 REST,您必须使用超文本作为应用程序状态引擎 (HATEOAS)。依赖于 URI 的客户端知识依赖于带外知识,这与 REST 是对立的。

您的资源不需要直接映射到您的业务对象。如果您选择,您可以将用户意图本身表示为资源,例如一个被禁止的玩家事件资源。您可以 POST 向它提供一些有关要禁止哪个玩家的信息,随后的 GET 将提供有关该事件的信息。

哦,仅仅因为 REST 不关心您的 URI 是什么,并不意味着您不应该关心。你只需要使用不同的标准来决定什么是最好的。

这篇 Google 带有超媒体控件的云文章 API design: Understanding gRPC, OpenAPI and REST and when to use them clarifies the REST vs RPC debate. REST is more relevant for entity-centric API whereas RPC is more relevant for action-centric API (and CQRS). The most mature REST level 3 仅适用于具有简单状态模型的实体。

首先了解并评估 REST 对您的案例的好处。许多 API 是 REST-ish 而不是 RESTful。 OpenAPI 实际上是 RPC 映射和 HTTP 端点,但这并不妨碍它被广泛采用。