Search code examples
architecturemicroservicesdomain-driven-designcqrs

Microservice Architecture - is there a Need to have API per service


I have been exploring Microservice Architecture, and even though the technologies I use are in Microsoft Domain, the question is generic.

I get the Idea of API Gateway esp for things like Authentication. The pattern I am roughly following is based on CQRS + Event Sourcing

Request-> Command ##CommandBus##->CommandHandler -> Change Aggregate State->Store Events-> PublishDomainEvents ->Publish Integration events ##Event Bus## -----> Update Read Models

Many times initial Command will be handled by ProcessManager (consumer) to Orchestrate workflow.

All Microservices Application Layer consume Command from Bus and work on changing Aggregate state. Once done, the Read model store is updated. Currently, there is only a single Read Database which is updated

When I started with Command Bus, The REST API per microservices were for mainly Get requests ( Read ), which would dip into the same Read Database as all other Services and rest for accepting Command from Gateway.

Based on my current Scenario, Is there a logic in having REST API's per Microservice? I know we can do Async with Rest API to push commands, but what is the point when I am already using a Bus.

But now I am thinking of not having API per Service but rather API's based on usage. It's then not limited to single Gateway but few Gateway API projects.

Are there any Cons/ pitfalls with this approach?

Edit 2-- **Trying to rephrase if it gives context ** My microservice structure is very similar (to what @mrdnk commented) . As you In I will introduce technology to make it more clear. I use Mass transit over RabbitMQ for inter service communication.

As of now I have API gateway used by client applications, which would then call appropriate microsservice API to push a command object. the API method itself acts as a Command Handler (acting as Application layer) calls Aggregate and make it undergo changes. Domain Events based on the change are published within the process with Mediatr. Any events that outside (microservice) world needs to know is published on the bus. I started to look at the communication and said to myself why not use the Bus also for commands (as command bus). That way I can have more reselient and async process.

Application layer will listen to command and handle appropriately. This way I feel the service is more encapsulated. On API side (individual microservce) I dont need to expose any rest api for use by gateway. API in Gateway wil listen to request and create command object. this will be queued to bus. Consumer (command handler) on Microservice will consume Command and so on.

Currently all Writes are eventsourced (mongodb). Reads go to SQL Server. I can create API just for Queries from Read side. No more need to have Http API from Microservice at all.

I know technically it would work but Dont know if there are any pitfalls.

Regards, Mar


Solution

  • I think it is a good idea to have Microservices communicate with each other asynchronously and in practice I also use this appraoch with a mix of orchestration and choreography depending on the use cases.

    Concerning the public API which you expose to your clients (e.g. web clients) over the internet it really depends on the determining factors and the options you are given. If your clients require REST based communication I would recommend to provide a fast response to the client synchronously by just providing the information that it went through Ok and some kind of unique id.

    So if you think of an order request of an online shop the API gateway would forward the request to the order Microservice (either via REST or in your case via Messaging and some translation from asynchronous to synchronous response at the API gateway layer). Anyway, there should be some kind of immediate response to the client the order service can provide which could simply contain the id of the new order. Everything else for processing the order will than happen asynchronously either completely via an event-based choreography (started by an OrderRequestReceived event or whatever name fits the domain language) or via some kind of workflow orchestrated by the order service (but still with asynchronous messaging).

    The client can then always use the order id to query the current state of the order which you will than provide based on the read model you are building.

    If you are free to implement the client the way want you can also look into WebSockets, using HTTP/2 to allow for pushing of status changes rather than requiring the clients to poll for the current state. Or you could even look into gRPC...