Despite the complexity of microservices, they are usually the ideal choice for complex applications. When you choose to build your application as a set of microservices, you need to decide how your application’s clients will interact with the microservices. With a monolithic application, there is just one set of endpoints, however, in a microservices architecture, each microservice exposes a set of what are typically fine-grained endpoints.
How will your application’s clients interact with the microservices?
Let’s look at an example of a Native mobile client for a shopping application:
The product details page contains lots of information
- Number of items in the shopping cart
- Order history
- Customer reviews
- Low inventory warning
- Shipping options
- Various recommendations
- Alternative purchasing options
By using a microservice architecture the data displayed on the product details page is owned by multiple microservices:
- Shopping Cart Service – number of items in the shopping cart
- Order Service – order history
- Catalog Service – basic product information, such as its name, image, and price
- Review Service – customer reviews
- Inventory Service – low inventory warning
- Shipping Service – shipping options, deadlines, and costs drawn separately from the shipping provider’s API
- Recommendation Service(s) – suggested items
So, we can create direct communication, or through an API.
Direct client-to-microservice communication
In theory, a client could make requests to each of the microservice directly. There are a few challenges and limitations with this option, such as:
- In the above example 7 separate API calls are needed. This becomes even more complicated for companies like Amazon, which has 100s of services involved in rendering their product page
- inefficient over the public Internet and would definitely be impractical over a mobile network.
- Some microservices might use protocols that are not web friendly (RPC, AMQP messaging). An application should use protocols such as HTTP and WebSockets outside of the firewall
- It would be difficult to refactor the microservices. For example, we might merge two services or split a service into two or more services.
- The number of service instances and their locations (host+port) changes dynamically
Using an API Gateway
By using an API gateway, we’re going through a server that is the single entry point into the system. This option encapsulates the internal system architecture and provides an API that is tailored to each client.
The API gateway offers various features, including:
- load balancing,
- request shaping and management, and
- static response handling.
It could also be responsible for request routing, composition, and protocol translation.
A product details scenario would include an endpoint (
/productdetails?productid=xxx) that enables a mobile client to retrieve all of the product details with a single request by invoking the various services, product info, recommendations, reviews, etc – and combining the results.
Example: The Netflix API Gateway
Netflix attempted to provide a one-size-fits-all API for their streaming service, and an API tailored for each device by running device specific adapter code.
By using an approach backends for frontends, they created a separate API Gateway for each kind of client.
Benefits and Drawbacks of using an API Gateway
- encapsulates internal structure of the application
- reduces the number of round trips between the client and application
- simplifies the client code
- Component that must be developed, deployed, and managed
- Developers must update the API Gateway in order to expose each microservice’s endpoints
While you can choose the approach that fits you best, we definitely recommend using an API gateway, as it will allow better control and easier scaling.
Which approach do you use when making a microservice application? Let me know in the comments.