对于 CQRS 命令,API 应该返回什么?

What should be returned from the API for CQRS commands?

据我了解,在通过 RESTful HTTP API 公开的面向 CQRS 的 API 中,命令和查询通过 HTTP 动词表达,命令是异步的通常 returning 202 Accepted,而查询会获得您需要的信息。有人问我以下问题:假设他们想更改一些信息,他们必须发送命令然后查询以获得结果状态,为什么可以简单地 return 强制客户端发出两个 HTTP 请求他们在单个 HTTP 请求的命令的 HTTP 响应中想要什么?

没有什么能阻止你这样做。如果您同步执行命令并同步创建投影,那么您可以轻松地在执行命令后直接进行查询并 returning 结果。如果您通过 rest-api 异步执行此操作,则您没有要发送回的查询结果。如果您在系统中异步执行此操作,则可以等待创建投影,然后将响应发送给客户端。

重要的是您以经典的 CQRS 样式将写入和读取模型分开。这并不意味着您不能在执行命令时在同一请求中进行读取。当然,您可以向服务器发送命令,然后使用 SignalR(或其他东西)等待您的投影已 created/updated 的通知。我没有看到等待在服务器端而不是在客户端创建投影的问题。

你如何做到这一点将影响你的基础设施和错误处理。此外,如果您 return 立即获得结果,您将保持 HTTP 请求打开更长时间。

几个月前 (link),我们在 DDD/CRQS 邮件列表中进行了一次长谈。讨论的一部分是 "one way command",这就是我认为您的假设。你会发现 Greg Young 反对这种模式。命令会更改状态,因此容易失败,这意味着它可能会失败,您应该支持这一点。带有 POST/PUT 请求的 REST API 对此提供了完美的支持,但您不应该只是 return 202 Accepted,而应该返回一些有意义的结果。有些人 return 200 成功,还有一些对象包含 URL 以检索新创建或更新的对象。如果命令处理程序失败,它应该 return 500 和一条错误消息。

使用即发即弃命令很危险,因为它会给消费者关于系统状态的错误想法。

我的团队最近也对这件事进行了非常激烈的讨论。感谢您发布问题。我通常是 "fire and forget" 风格命令的捍卫者。我的立场一直是,如果你希望有一天能够转移到异步命令调度程序,那么你不能允许命令 return 任何东西。这样做会扼杀你的机会,因为异步命令没有太多方法可以 return 原始 http 调用的值。我的一些队友真的挑战了这种想法,所以我不得不开始思考我的位置是否真的值得捍卫。

然后我意识到异步与否只是一个实现细节。这让我意识到,使用我们的框架,我们可以构建中间件来完成我们的异步调度程序正在做的同样的事情。因此,我们可以按照我们想要的方式构建我们的命令处理程序,returning 任何有意义的东西,然后让处理程序周围的框架处理 "when".

示例:我的团队目前正在 node.js 中构建一个 http API。我们不需要 POST 命令只 return 空白 202,而是 returning 新创建资源的详细信息。这有助于前端继续前进。前端 POSTS 是一个小部件,并使用与频道名称相同的命令打开到服务器的网络套接字的频道。请求到达服务器并被中间件拦截,中间件将其传递给服务总线。当命令最终由处理程序同步处理时,它 "returns" 通过网络套接字并且前端很高兴。可以轻松禁用中间件,使 API 再次同步。