Last updated on September 25th, 2023
In my previous post, I introduced the process of building an authorization server, which serves as my starting point for delving into the world of microservices. In this post, I will go into the theory of the API gateway pattern. The implementation details for each function of it will be discussed in upcoming posts.
A problem arises when clients access internal services directly
Consider an application that allows users to send messages and points to other users. The application must interact with three separate backend services: point service that manages user points, including point transactions and balance checking, messaging service that handles messages sent and received between users, including message content and attachments and profile service that maintains user profile data.
The common approach is the mobile application communicates directly with each service using their respective endpoints. It’s straightforward, but not practical for a client to perform API composition over the internet, leading to a couple of issues:
- Network latency due to multiple requests
Imagine a simple case where a transaction is made in the above example. To send a message and point to another user, the mobile app would first need to request the recipient’s profile information from the Profile Service. Then, it would have to connect to the Messaging Service to send the message. Finally, the app needs to interact with the Point Service to process the point transactions. These multiple requests can lead to a poor user experience as it increases the loading time and network latency.
- Lack of Encapsulation. Any changes in the backend services can directly impact the mobile application.
With this architecture, if the endpoint structure for one of the services changes, the mobile app would need to update the corresponding code in their application. This direct dependency between frontend and backend systems makes it difficult to maintain.
- Backend services might use various IPC mechanisms that are not supported by the mobile application
The services may not use HTTP; instead, they could choose gRPC for example. In this case, the mobile app would need to find ways to consume those protocols. This extra layer of complexity could lead to increased development time and potential integration issues.
So we can see that the above approach doesn’t seem to be suitable. A much better approach is to make a single request to an API gateway. Let’s explore how it works.
The API Gateway Pattern
An API gateway is a service that is the entry point into the application from the clients. It encapsulates our internal services and provides an API to its clients. It sits between the clients and a collection of backend services for the application, serving important functions:
- Request routing
- Protocol translation
- Authentication and authorization
- Rate limiting
- Monitoring, logging, analytics and billing
- Caching
I’ll implement each function consecutively in the upcoming posts.
Drawbacks of API Gateway pattern
API Gateway pattern offers numerous benefits; however, it also introduces a couple of drawbacks to consider when implementing this pattern.
An API gateway adds another layer of processing to client requests, which can introduce latency in response times, particularly when handling increased traffic loads.
There’s also a risk that the API gateway becomes a development bottleneck. Basically, it serves as the central point of access for all client requests, potentially becoming a bottleneck and single point of failure in the system.
An API gateway adds another layer of abstraction to the system, increasing overall architectural complexity.
API Gateway and Backend for Frontend (BFF)
One of the challenges in implementing an API Gateway is accommodating the need for slightly different data by various clients. In such cases, we can apply an API Gateway along with a BFF.
BFF refers to the practice of creating separate and customized backend services that are tailored for specific client types, such as web, and mobile. Each BFF serves as a facade to the underlying MS and coordinates interactions between the client and these services.
BFF focuses on providing a client-oriented experience, tailoring backend services specifically for a type of client, while API Gateway centralizes the point of access to Microservices and manages requests for all clients.
BFF and API Gateway can work together. BFFs can be created for specific clients, such as a web application or a mobile app, while the underlying services being accessed by the BFF can still be exposed through an API Gateway.
API gateway flow
This part is my note of API gateway flow from this video
- The client sends a request (HTTP-based) to the API gateway. It could be REST, GraphQL,…
- The API Gateway validates the HTTP request.
- The API Gateway checks the caller’s IP address and other HTTP headers against its allow-list and deny-list. It could also perform basic rate limit checks against attributes such as IP address and HTTP headers.
- The API Gateway forwards the request to an identity provider to handle authentication and authorization.
- A more comprehensive rate-limit check is applied based on the authenticated session. If the request exceeds the defined limit, it is rejected at this stage.
- Leveraging a service discovery component, the API gateway identifies the appropriate backend service to process the request through path matching.
- The API gateway transforms the request into the appropriate protocol and sends the transformed request to the backend service, for instance, using a protocol like gRPC. Upon receiving the response from the backend service, the API gateway then converts the response back to the public-facing protocol and delivers it as a response to the client.
Next steps
In this post, I have covered the theory of the API Gateway Pattern. To sum up, the API gateway is a single entry point for all client types to access backend services in an MS architecture. It is responsible for handling request authentication, routing, and protocol translation, as well as aggregating and transforming data when necessary. It aims to provide a unified way for clients to access multiple MS, thus reducing the complexity and latency associated with direct communication.
In the upcoming posts, I’ll implement the API Gateway pattern. While there are numerous technologies available for implementing an API gateway, including off-the-shelf products, I will develop my own API gateway using the Spring Cloud Gateway framework. It should cover the following functions:
- Authentication and authorization
- Rate limiting
- Monitoring, logging, analytics and billing
- Caching