假设您有一个模型Foo。 一个业务案例是简单地创建一个Foo实例,因此我的模型中有一个相应的CreateFooCommand,通过调用给定REST端点的POST请求来触发。
当然还有其他命令。
但是现在,有一个ViewModel,它来自我的DomainModel 派生。它只是一个带有原始数据的sql表 - 来自DomainModel的每个Foo实例都有相应的派生ViewModel实例。两者都有不同的ID(在DomainModel上有一个DomainID,在ViewModel上它只是一个long
值。)
现在:在这种情况下我是否应该关心HATEOAS?在适当的REST实现中,我至少应该在标头中返回location-url。但由于我的视图模型仅来自DomainModel,我应该关心吗?在我的DomainModel创建时,我甚至没有查看模型的ID。
答案 0 :(得分:10)
由于CQRS意味着查询与命令分离,因此您可能无法立即执行查询,因为命令可能尚未应用(可能永远不会)。
为了与HATEOAS协调,而不是从POST请求返回200 OK,服务可以返回202 Accepted:
请求已被接受处理,但处理尚未完成。该请求最终可能会或可能不会被执行,因为在实际处理时可能不允许该请求。没有从异步操作中重新发送状态代码的工具。
202回复是故意不承诺的。其目的是允许服务器接受对某些其他进程的请求(可能是每天只运行一次的面向批处理的进程),而不要求用户代理与服务器的连接持续到进程完成为止。通过此响应返回的实体应该包括请求的当前状态的指示,以及指向状态监视器的指针,或者某个用户可以期望满足请求的估计值。
(我的重点)
该指针可以是客户端可以查询以获取Command状态的链接。当/如果命令完成并且视图已更新,则该状态资源可以包含指向视图的链接。
这几乎是REST in Practice的工作流程 - 非常让人想起它的 Restbucks 示例。
处理ID问题的另一个选择是在接受命令之前生成ID - 甚至可能要求客户端提供ID。详细了解此类选项here。
答案 1 :(得分:1)
正如Greg Young解释的那样,CQRS只不过是“将一个对象分成两个”。因此,假设您有一个域聚合并且它具有id。现在你在谈论你的视图模型有另一个id。但是,除非视图模型中也包含聚合ID,否则无法更新视图模型。从我的角度来看,您的REST POST请求应返回其中包含聚合ID的结果。这个是您的ID,除了读模型存储之外,任何人都不关心视图模型ID。
它是否应该返回命令状态URI,如Mark建议的是另一个讨论的主题。目前,许多CQRS从业者倾向于同步处理命令以避免在发生故障时FE / BE不匹配,并使FE能够对BE上的错误作出反应。没有真正的胜利来为一个用户异步执行命令。命令会改变状态,在99%的情况下,用户需要知道状态是否正确变异。