Ashniu123 / nestjs-customer-order-eventsourcing-cqrs

Nestjs project with simple customer and order cqrs using Kafka as EventBus
26 stars 5 forks source link

Get Requests #1

Open kodeine opened 3 years ago

kodeine commented 3 years ago

Really like your efforts with this lib. A question that arise is why GET request is on the View/ Query side? This means creates/deletes/updates are done async on port 3001 but gets need to be done customer view svc on port 3002?

Is there a way to use kafka to get the list of customers? Or a microservice layer needs to be added on customer view svc so customer-svc can proxy that request and fetch the data and present?

What if we want a stream of all customers and updates...thru websockets.. so we subscribe to get and any new events gets pushed to websocket as well and UI can be updated.

Error Handling: How can we handle error handling, for example, [CreateCustomerEventHandler] Failed to create customer: MongoError: E11000 duplicate key error collection how can we return this as the api response?

Ashniu123 commented 3 years ago

Hey @kodeine. Thanks for your interest in this repo.

A question that arise is why GET request is on the View/ Query side?

That is how CQRS works. Another way to do it is to have all endpoints hit an API Gateway and then route to services depending on the action(C or Q).

Is there a way to use kafka to get the list of customers? Or a microservice layer needs to be added on customer view svc so customer-svc can proxy that request and fetch the data and present?

We could get the customer ids from Kafka, and then fetch complete information from the customer view svc (by having a batch endpoint added).

What if we want a stream of all customers and updates...thru websockets.. so we subscribe to get and any new events gets pushed to websocket as well and UI can be updated.

Yes. That is also possible. I assume you're talking about frontend only since Kafka can relay information between services easily. The best way to do so would be through GraphQL as an API Gateway (another service which sits on top of the services now), and leverage their subscriptions. Alternatively, our own logic for WebSocket to frontend can also be implemented wherein each service can emit data they processed.

This repo does provide a base for all what you have asked about. Feel free to fork it and expand/improve upon it. :)

kodeine commented 3 years ago

Thank you for your response, one more question, we aren't using sagas in this repo. Where should I trigger more events. Like after create customer event I would want create customer profile event. Where i should trigger it? Actually a pseudo code would be helpful

I also see that a reply is not received it just sends the event without looking for event reply. Is that correct?

Thanks

Ashniu123 commented 3 years ago

Reference for using Sagas in nestjs is here.

In addition to the above, you'll have to add the following code (not in the official nestjs documentation)

import { CustomerSagas } from './customer.sagas';

export class AppModule implements OnModuleInit {
constructor(
... // other members
private readonly customerSagas: CustomerSagas,
) {}

async onModuleInit() {
    // event bus register, etc
    this.event$.registerSagas([this.customerSagas.customerCreated]); // add other sagas also
}

This will enable the eventbus to trigger sagas, as the events are published to the bus (here, Kafka).

kodeine commented 3 years ago

Lovely, thank you.

kodeine commented 3 years ago

And right now the Kafka module just emits the event, I wasn't able to receive the event reply.

Cqrs queries will need that so frontend can know about responses

Ashniu123 commented 3 years ago

And right now the Kafka module just emits the event, I wasn't able to receive the event reply.

You can return the "Record" that is sent by the producer.

Though the reason why publish won't return any value is because of how the CQRS module works.

You will have to modify the CommandHandler to use the eventBus directly. Something like

// create-customer.command-handler.ts

async execute(command: CreateCustomerCommand) {
/* 
const customer = this.publisher.mergeObjectContext(
      await this.customerAdapter.createCustomer(customerId, createCustomerDto),
    );
    customer.commit();
*/
const records = await this.eventBus.publish(
        new CreateCustomerEvent(customerId, createCustomerDto),
      ),
}

And then return some value from execute function to indicate to the AppService to return 200 or 400 or 500 status code.