CQRS 命令和 GraphQL 突变

Posted

技术标签:

【中文标题】CQRS 命令和 GraphQL 突变【英文标题】:CQRS commands and GraphQL mutations 【发布时间】:2020-11-09 21:57:12 【问题描述】:

我刚刚了解了 CQRS,我想将它与基于 GraphQL 的 API 结合到一个项目中。然而,为了做到这一点,我想到了一个问题:根据 CQRS,命令在执行后必须不返回任何内容。但是,根据 GraphQL 约定,突变必须返回实体的更新状态。

我应该如何处理? CQRS 和 GraphQL 不兼容吗?我想到的唯一解决方案是,为了解决突变,首先执行命令,然后执行查询,以获得响应对象。还有什么比这更好的吗?对我来说它看起来不是很有效......

提前致谢

【问题讨论】:

【参考方案1】:

我应该如何处理?

真正的答案?忽略“必须不返回任何东西”的约束;该约束背后的基本假设不成立,因此您不应该过分依赖它。

具体怎么做取决于你的设计。

例如,如果您在处理 HTTP 请求的同一进程中更新域模型,那么 (a) 保存域模型,(b) 运行视图投影 是完全合理的事情您刚刚保存的模型的副本,(c) 然后返回视图。

换句话说,信息经过与“通常”完全相同的转换,除了我们同步执行这些转换,而不是异步执行这些转换。

如果模型在不同的过程中更新,那么事情会变得更加棘手,因为需要更多的消息传递,并且您可能需要处理超时。例如,您可以想象一个解决方案,您发送命令,然后轮询“读取端”,直到该模型更新以反映您的更改。

这都是权衡,而这些权衡是选择分布式架构的必然结果。我们选择 CQRS 不是因为它让一切变得更好,我们选择 CQRS 是因为它让一些事情变得更好,另一些事情变得更糟,而且我们所处的环境中,它让事情变得更好比事情变得更糟。

【讨论】:

加几美分,您可以将 Mutation 返回视为来自 CQRS 的查询。 @RodrigoBoratto 你的意思是在突变后使用读取模型进行额外查询吗? 取决于您如何进行查询(和用例),是的。如果你有一个缓存层,可能突变已经改变了它,在返回之前你可能需要一些实体到模式的映射。我通常做的只是返回“模式 ID”,让 GraphQL 处理其余的,主要是因为我使用联合模式,而某些“属性”只存在于其他服务上。 schema_id 是否与 entity_id 相同? let the GraphQL handle the rest 你的意思是客户端重取吗?【参考方案2】:

我正在考虑类似的情况,即主要使用 GraphQL 与基于 CQRS 的系统的读取端进行交互。

然而,在写入方面,我正在考虑使用一个 Web 或 REST API,它有一个接受命令的端点。

请记住,在 CQRS 中,您不会直接改变实体,而是提交一个命令来表明您的意图/想要做某事。

或者,在这里大声思考,可以使用 GraphQL 中的突变来创建命令并使用订阅跟踪它们的状态。

【讨论】:

我明白你的意思,但我不完全喜欢为查询和命令设置单独的端点的想法......你有没有想过打破 GraphQL 关于返回更新实体的“规则”作为结果的突变,而不是只返回一个自定义类型,比如“提交的命令”? 是的,都可以用 GraphQL 完成,但是(正如我的帖子所建议的)我可能只使用一种 GraphQL 命令类型,提交命令并以接受或拒绝(通过命令处理程序)状态返回命令更新和命令标识符,以供将来查询或订阅有关命令状态。 我还想讨论一下,突变返回的内容取决于您。根据 GraphQL,它也可能什么都没有并且没问题。您只需要从客户端重新查询数据,而不是获取更新的响应对象,以使客户端的本地缓存正确。

以上是关于CQRS 命令和 GraphQL 突变的主要内容,如果未能解决你的问题,请参考以下文章

我们如何从 GraphQL 的 RequestContextHolder 获取 GraphQL 的 HttpServletRequest(DefaultGlobalContext)(使用 graphq

无法使用 graphq-request 表示嵌套对象输入类型的数组

使用 GraphQL API 的清洁架构 CQRS

如何在突变 graphQL Playground 中传递变量?

Graphql 突变以上传具有其他字段的文件

从另一个突变中调用 GraphQL 突变?