为什么我应该更喜欢 HTTP REST 而不是 HTTP RPC JSON-消息传递样式与 CQRS 结合使用?

Why should I prefer HTTP REST over HTTP RPC JSON-Messaging style in conjunction with CQRS?

每次我读到 Web 服务应该如何通信时,首先想到的是:

Use REST, because it decouples client and server!

我想构建一个 Web 服务,其中每个 QueryCommand 都是一个 Http-Endpoint。使用 REST 我会有更少的端点,因为它考虑 resources 而不是 operations 的性质(您通常拥有比资源更多的操作)。

附加信息:消息传递我的意思是同步消息传递请求/回应)

更新: 我认为只有一个可以处理 QueryCommand 的 Http 端点也是 possible/better取决于给定的 Http 动词。

最好的答案可能是 "it depends",但真正的 REST 的一大优点是它是无状态的。无国籍意味着各种各样的事情。

基本上,如果您查看 HATEOAS 约束,您就会知道解耦的原因 1

认为 RPC-JSON 本身不是有状态的,但它肯定没有被定义为无状态的。因此,对于为什么与 REST 的解耦非常高,您有最有力的论据。

1: https://en.wikipedia.org/wiki/HATEOAS , http://restfulapi.net/hateoas/

在开始 CQRS 部分之前,我想花一点时间谈谈 REST 的优点和缺点。在我们就何时以及为何使用 REST 达成共识之前,我认为不可能回答这个问题。

休息

与大多数其他技术选项一样,REST 也不是灵丹妙药。它有优点也有缺点。

我喜欢用Richardson's Maturity Model, with Martin Fowler's additional level 0作为思考工具

0 级

Martin Fowler 也称级别 0 POX 的沼泽,但我认为真正区分这一级别的只是使用 RPC over HTTP。它不一定是 XML;它可能是 JSON 而不是。

此级别的主要优势是互操作性。大多数系统可以通过 HTTP 进行通信,大多数编程平台可以处理 XML 或 JSON.

缺点 是系统很难独立于客户端发展(见第 3 级)。

这种风格的显着特征之一是所有通信都通过一个端点。

1 级

在第 1 级,您开始将 API 的各个部分视为单独的资源。每个资源都由 URL.

标识

一个 优点 是您现在可以开始使用现成的软件,例如防火墙和代理服务器,来控制对系统各个不同部分的访问。您还可以使用 HTTP 重定向将客户端指向不同的端点,尽管在这方面存在一些缺陷。

我想不出有什么缺点,除了0级

2 级

这个级别,你不仅有资源,而且还会使用HTTP动词,如GETPOSTDELETE

一个优势 是您现在可以开始更多地利用 HTTP 基础结构。例如,您可以指示客户端缓存对 GET 请求的响应,而其他请求通常不可缓存。同样,您可以使用标准的 HTTP 防火墙和代理来实现缓存。您可以免费获得 'web-scale' 缓存。

第 2 级建立在第 1 级之上的原因是您需要每个资源都是独立的,因为您希望能够独立于彼此缓存资源。如果您无法区分各种资源,或者您无法区分读取和写入,则无法执行此操作。

缺点是它可能涉及更多的编程工作来实现它。此外,所有先前的缺点仍然适用。客户端与您发布的 API 紧密耦合。如果您更改 URL 结构,客户就会中断。如果您更改数据格式,客户端会中断。

尽管如此,许多所谓的 REST API 都是在这个级别设计和发布的,因此在实践中,许多组织似乎发现这是优缺点之间的一个很好的权衡。

3 级

这是我认为真正的 REST 的 REST 设计水平。这与以前的级别完全不同;这是设计 API 的完全不同的方式。在我看来,0-2 级和 3 级之间存在明显的区别。

级别 3 的一个显着特征是 you must think content negotiation into the API design。不过,一旦你有了它,选择这种 API 设计风格的原因就会变得更加清晰。

对我来说,第 3 级 APIs 的主要 优势 是您可以独立于客户发展它们。如果您小心,您可以在不破坏现有客户端的情况下更改 API 的结构,甚至是导航图。如果您需要引入重大更改,您可以使用内容协商来确保客户端可以选择加入重大更改,而旧版客户端将继续工作。

基本上,当我被要求写一个我无法控制客户端的 API 时,我的默认选择是级别 3。

设计 3 级 REST API 需要您以一种对许多人来说不寻常和陌生的方式进行设计,因此这是一个 缺点 。另一个缺点是客户端开发人员经常发现这种 API 设计风格不熟悉,因此 they often try to second-guess, or retro-engineer, your URL structure。如果他们这样做,你将不得不花费一些努力来阻止他们也这样做,因为这将阻止你进化 API.

换句话说,级别 3 API 需要大量的开发工作,尤其是在服务器端,但客户端也变得更加复杂。

不过,我要重申其优点:您可以独立于客户端发展 3 级 REST API。如果您不控制客户端,则向后兼容性至关重要。级别 3 使您能够在保持兼容性的同时进化 APIs。我不知道您可以使用任何其他样式实现此目的的方法。

CQRS

现在我们已经确定了 REST 的一些优点和缺点,我们可以开始讨论它是否适用于 CQRS。

Greg Young 和 Udi Dahan 关于 CQRS 最基本的共识是 it's not a top-level architecture

简而言之,原因是构成 CQRS 系统的消息(命令和事件)和查询对解释很敏感。为了某事,客户端必须知道发出哪个命令,而服务器必须知道如何解释它。因此,该命令是系统的一部分。

系统可能分布在客户端和服务器上,但消息和数据结构是相互耦合的。如果您更改服务器解释给定消息的方式,该更改将影响您的客户端。您不能在 CQRS 架构中独立发展客户端和服务器,这就是它不是顶级架构的原因。

因此,鉴于它不是顶层架构,传输架构变得相当无关紧要。从某种意义上说,发送消息唯一需要的是单个 'service bus' 端点,如果您需要的只是互操作性,那么它很容易成为 0 级端点。毕竟,您唯一要做的就是将消息放入队列。

那么,最终答案一如既往:视情况而定。

交货速度是最重要的标准吗?你能同时控制所有的客户端和服务器吗?那么,也许 0 级就是您所需要的。也许2级就可以了。

另一方面,如果您有无法控制的客户(移动应用程序、硬件 (IoT)、使用您的 public API 等的业务合作伙伴),您 必须 考虑如何处理向后和向前兼容性,在这种情况下,(IMO) 需要 3 级。不过,在那种情况下,我建议保留 CQRS 的实现细节。