Microservices Architecture, The Hard Parts : Data Query using API Composition Pattern

Naresh Waswani
Simpplr Technology

--

Microservices Architecture is easy to visualize but hard to implement to take full advantage of it. A microservice owns the data and a client getting data from a data owner service is well understood but there will always be a situation where a client needs data from more than one service to fulfill a use case it’s trying to implement. This situation is not easy to implement and needs some thought process on how best it can be realized.

There are ways to handle such a query pattern in Microservices Architecture and one of the ways which can help handle such a situation is API Composition Pattern.

Let’s look at a use case where we need such a pattern —

Assume as a business requirement, while rendering a Content page on UI (Web or Mobile), we need to show the comments made by users on the content, reactions given by the users and recommended content for content discovery and promotion.

The team has realized the domain problem using Microservices Architecture with services as —

  1. Content Service
  2. Comments Service
  3. Reactions Service
  4. Content Recommendation Service

The user interface in this situation wants to get data of a specific content, its comments, reactions and similar content from the backend and render it on the UI.

Aren’t the given services too fine grained and some of them can be clubbed together — Well, as the saying goes, “It Depends” on the overall domain problem we are trying to address. And the purpose of this blog is to show, given a situation like this, how we can handle querying of data across multiple services.

Here is the simplest approach which can help to solve this situation —

Client orchestrating the API calls to query data as needed

The approach above is easy to visualize and implement and the service teams are least aware of other domains but it has quite a few issues —

  1. Client (UI) is made aware of the different domain services that should be invoked to fulfil the request, hence there is a domain coupling being added here.
  2. Latency impact because of multiple network calls being made to get the data from different backend microservices, aggregate it on the client side and then render it.
  3. Complexity involved in handling errors should the APIs fail to respond.

How do we handle some of the cons mentioned above? Well, we can use the API Composition pattern.

In this pattern, we have an API Composer component which sits between the client and data provider services. This component exposes an API for the client to invoke and behind the scenes it gets data from other services, aggregates it and responds back to the client.

API Composition pattern to aggregate data from multiple data services

Because the end client (UI/Mobile client) needs to invoke only a single API call to get the required data, the latency impact because of multiple network calls is gone. Plus, the API clients are no longer coupled with the domain services as they are not orchestrating the API calls, and are least aware of the domain services providing the data.

But an important design question which needs to be answered is — which component is responsible for API Composition? Well, there are two possible solutions to it —

Option 1 - One of the Domain services owns this responsibility

Domain Service with additional responsibility of API Composer

In this option, the service has a domain coupling with other services and hence the team needs to enhance their service to support this use case.

Option 2 - Have a new component service for API Composition

With Modern Day Architecture, Microservices are generally exposed via API Gateway. And one of the features of API Gateway is to do API Composition.

API Gateway being used for API Composition

With this option, the domain services continue to focus on their domain and hence no domain coupling with other services. But now you have an additional component to be managed, most probably in a shared capacity as the API Gateway might be acting as API Composer for many of the domain services.

Overall, the API Composition pattern is a simple pattern to implement, offers some of the advantages in handling error scenarios and could also help in increasing the API performance if the situation allows it. Some of the pros are listed below —

  1. Client has a single interface to talk to. Any change happening on the data provider services has no impact on the client. It will be absorbed by the API Composer layer.
  2. Implementation/Orchestration details is hidden from the clients — API Composer can internally help transform data received from provider services or can also do protocol conversion if the data provider services are using different protocols. Example — REST, SOAP, HTTP, etc.
  3. API Composer can cache the data if needed, and hence can improve the API performance.
  4. If one of the data provider services is not responding, API Composer can respond with the cached data or may simply omit the data and respond back with the rest of the data set.
  5. Can help to fail fast — Referring to the content use case above, the main data entity in the use case is Content and other entities are secondary data. If Content service is not responding, the API Composer component can respond immediately with an error code, without making additional network trips to get rest of the data from other provider services.

But as they say, every pattern has some cons and this pattern is not an exception. Listed below are some of the cons —

  1. Multiple services are being invoked to get the data and aggregate it, which consumes additional compute and network resources. Plus, an additional overhead of development and maintenance effort — implementing in an optimized way, if calls to services can be made in parallel or sequential, handling all error scenarios gracefully, etc.
  2. With so many service to service network calls, there is dynamic coupling being added here, which reduces the overall availability of the composer service.
  3. Can be a single point of failure.
  4. If the data received from the provider services is large, in-memory aggregation may impact the performance of the API.

With majority of the use cases, API Composition pattern can be easily used but there could be some use cases where the API Composer may have to deal with large amounts of data to perform join and transformation, which technically could be doable but may not be efficient and would lead to high latency. In such situations there is another pattern which could be used — CQRS. Will cover this pattern in my next blog.

Hope you enjoyed reading this blog. Do share this blog on social media if this has helped you in any way.

Happy Blogging…Cheers!!!

#MicroservicesQuery #MicroservicesCQRS #MicroservicesAPICompsition #APICompositionPattern

--

--

Naresh Waswani
Simpplr Technology

#AWS #CloudArchitect #CloudMigration #Microservices #Mobility #IoT