doug-martin / nestjs-query

Easy CRUD for GraphQL.
https://doug-martin.github.io/nestjs-query
MIT License
823 stars 142 forks source link

Using with CQRS pattern #775

Open kodeine opened 3 years ago

kodeine commented 3 years ago

So how can we use the resolvers with a cqrs pattern, basically we need to use a command bus. What would be the best approach to handle this use case.

FBurner commented 3 years ago

That would be quite interesting.

smolinari commented 3 years ago

@kodeine - https://docs.nestjs.com/recipes/cqrs

Scott

FBurner commented 3 years ago

@smolinari i think that was not a question on how to use cqrs in nestjs but how to connect nestjsquery with the cqrs module. That means nestjquery should generate commands and queries on the command bus instead of using mongoose directly like

 NestjsQueryMongooseCQRSModule.forFeature([
          { document: TodoItemEntity, name: TodoItemEntity.name, schema: TodoItemEntitySchema },
        ]),

And this would generate commands, provide command and eventhandlers, and use queries with query handlers

Edit: Is there any plan to extend nestjs query to use with cqrs, i think its not applicable for cqrs in the current state?

meodemsao commented 3 years ago

I think we need have plan for this

smolinari commented 3 years ago

I had been contemplating this a couple of weeks ago (and forgot about this issue). I was looking to also use CQRS to decouple module groupings (for creating sub-applications or application extensions). However, when I started mapping things out in my mind and on paper, it seemed so clear that I was doubling up a lot of stuff. In the end, I decided GraphQL represents commands and queries via mutations and queries. You have to think beyond GraphQL as a "query language" and more at its RPC nature. Mutations ARE commands in the end and in fact, I believe they should have called it that to avoid the misconception of GraphQL just being "CRUD"dy. It isn't. Mutations can call any kind of method to basically do anything.

Yes, there aren't command and query buses with GraphQL per se. Or rather, nothing has that nomenclature directly. But, if you think about the client and the calls to the endpoint(s), the client/server team up to form the two buses. On top of that, we have Subscriptions, which can be the responses to commands ( mutations). Again, I say, GraphQL is a form of CQRS itself.

The only thing missing is the SAGA pattern, which in effect, could (should) be on the client (talking about Mobile devices/ SPAs, etc) for application workflow. Imagine the client with a SAGA pattern to call mutations and queries to get an end result.

You could, in effect, use the mutations and queries (via the resolvers) to call a messaging service directly, which then is an event bus system and could even work off of an event store or any other messaging service. We have the separation already.

So, IMHO, adding CQRS to GraphQL is adding an unnecessary layer of duplicated abstraction. I feel it has no added benefits so I dropped the idea.

My 2 cents.

Scott

meodemsao commented 3 years ago

@smolinari in this project. https://github.com/juicycleff/ultimate-backend he seem success with graphql with cqrs. i think cqrs is good for microservice

smolinari commented 3 years ago

@meodemsao - Did you even look at the code?

Scott

applicationSPS commented 3 years ago

@smolinari How is this duplicated abstraction?

GraphQL is a query language like Json API would be.

CQRS is a Pattern to describe separation of concerns within the persistence handling.

Maybe Graphql seem to have similarities but it is a completely different layer.

While Graphql alows losely compling of services toward a model.

CQRS allows complex and entire different read and write processes with almost unlimited depth and decoupling.

The command (Mutation) of graphql ends at the resolver while the command of cqrs is maybe forwarded or triggeres other events within the application.

If you dont need that complexity of events, cqrs and graphql looks like overengineering. But if you need to have full flexibility in handling data exchange, aggregation, side effects, rolebacks, notifications. Aggregate events etc.

smolinari commented 3 years ago

@applicationSPS - The mutation of a GraphQL resolver can also trigger other events and services.

My point is, GraphQL already does a form of CQRS at the client level, instead of the server level. If you see it that way, then adding CQRS additionally to the server is adding a layer of abstraction not really necessary. Or do you think Facebook or Netfilx or Github or add any big user of GraphQL has CQRS going on behind their gateways? I know, for instance, Netflix doesn't. It makes no operational sense in a GraphQL gateway world.

The only thing that isn't explained with GraphQL is the ability to do distributed transactions aka Sagas or the saga pattern. I've not figured that one out yet. 🤷 But, theoretically, sagas could be kicked off by special mutations, which would be out of the scope of the project too.

I'm personally fairly certain this library doesn't need CQRS added to it. That is only my 2 cents and that is about as much as my opinion is worth.

Scott

applicationSPS commented 3 years ago

@smolinari those are not events you trigger, you forward requests thats not what events are about.

Graphql is not a form of cqrs.

And my guess is that they dont use CQRS Mostly because the just used GraphQL to get more services in their existing models without having to change the behaviour of legacy applications.

Netflix is using cqrs for their licencing service but that doesnt tell if they used graphql above it or the other way around.

And if you like to have mutations for sagas, mutations are still somehow coupled to a resolver or cant wait for another event, those are totally different things.

Its like using json api above cqrs or rest/controller with cqrs completely different patterns and layers with different benefits and drawbacks. :/