microservices-api-gateway/README.md
The API Gateway design pattern aims to provide a unified interface to a set of microservices within a microservices architecture. It acts as a single entry point for clients, routing requests to the appropriate microservices and aggregating results, thereby simplifying the client-side code.
Real-world example
In a large e-commerce platform, an API Gateway is used as the single entry point for all client requests, simplifying client-side development. When a user visits the site or uses the mobile app, their requests for product information, user authentication, order processing, and payment are all routed through the API Gateway. The API Gateway handles tasks such as user authentication, rate limiting to prevent abuse, and logging for monitoring purposes, enhancing overall security optimization. This setup simplifies the client interface and ensures that all backend microservices can evolve independently without affecting the client directly, thereby enhancing microservices communication. This also enhances security by providing a centralized point to enforce policies and monitor traffic.
In plain words
For a system implemented using microservices architecture, API Gateway is the single entry point that aggregates the calls to the individual microservices.
Wikipedia says
API Gateway is a server that acts as an API front-end, receives API requests, enforces throttling and security policies, passes requests to the back-end service and then passes the response back to the requester. A gateway often includes a transformation engine to orchestrate and modify the requests and responses on the fly. A gateway can also provide functionality such as collecting analytics data and providing caching. The gateway can provide functionality to support authentication, authorization, security, audit and regulatory compliance.
Sequence diagram
This implementation shows what the API Gateway pattern could look like for an e-commerce site. TheApiGateway makes calls to the Image and Price microservices using the ImageClientImpl and PriceClientImpl respectively. Customers viewing the site on a desktop device can see both price information and an image of a product, so the ApiGateway calls both of the microservices and aggregates the data in the DesktopProduct model. However, mobile users only see price information; they do not see a product image. For mobile users, the ApiGateway only retrieves price information, which it uses to populate the MobileProduct.
Here's the Image microservice implementation.
public interface ImageClient {
String getImagePath();
}
public class ImageClientImpl implements ImageClient {
@Override
public String getImagePath() {
var httpClient = HttpClient.newHttpClient();
var httpGet = HttpRequest.newBuilder()
.GET()
.uri(URI.create("http://localhost:50005/image-path"))
.build();
try {
var httpResponse = httpClient.send(httpGet, BodyHandlers.ofString());
return httpResponse.body();
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
return null;
}
}
Here's the Price microservice implementation.
public interface PriceClient {
String getPrice();
}
public class PriceClientImpl implements PriceClient {
@Override
public String getPrice() {
var httpClient = HttpClient.newHttpClient();
var httpGet = HttpRequest.newBuilder()
.GET()
.uri(URI.create("http://localhost:50006/price"))
.build();
try {
var httpResponse = httpClient.send(httpGet, BodyHandlers.ofString());
return httpResponse.body();
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
return null;
}
}
Here we can see how API Gateway maps the requests to the microservices.
public class ApiGateway {
@Resource
private ImageClient imageClient;
@Resource
private PriceClient priceClient;
@RequestMapping(path = "/desktop", method = RequestMethod.GET)
public DesktopProduct getProductDesktop() {
var desktopProduct = new DesktopProduct();
desktopProduct.setImagePath(imageClient.getImagePath());
desktopProduct.setPrice(priceClient.getPrice());
return desktopProduct;
}
@RequestMapping(path = "/mobile", method = RequestMethod.GET)
public MobileProduct getProductMobile() {
var mobileProduct = new MobileProduct();
mobileProduct.setPrice(priceClient.getPrice());
return mobileProduct;
}
}
Benefits:
Trade-offs: