The back-end service on our team started with just one big service, everything was written into it, and you can imagine how difficult it would become to maintain as the service grew bigger and bigger. Gradually, some data services were separated into separate API services, leaving some template rendering, data aggregation and some coupled business logic in the original services. It’s not clean enough so far, but our goal is to make the old service act as an API Gateway, or an intermediate layer for the front end. The single responsibility principle is an important way to decouple a service that does one thing well. By chance, I read the following article. Although it was only a simple introduction, I learned a lot from it. And I want to share it with you.

Read the original

Clients generally need to pass some authentication and meet security requirements during data transmission to gain access to services in the microservices architecture. Different services have more or less differences in authentication, and the API Gateway is like a hub that smooths out differences between service protocols and allows for special processing for specific clients. His existence facilitates the client to enjoy all kinds of services.

Microservices and consumers

Microservices are suitable for architecture where teams can independently design, develop, and run services. It allows for technical diversity across services in the system, allowing teams to use the right development language, database, and network protocol in the right scenario. For example, one team might use JSON and HTTP REST, while another might use gRPC and HTTP/2 or a message broker like RabbitMQ.

There are scenarios where different data serialization methods and protocols can be beneficial, but the clients that need to use our services may have different requirements. Because there are so many different clients, there are so many different data formats that we need to support. For example, one client may want data in XML format, while another may want data in JSON format. Another problem you may face is that there may be some common logic between different services (such as permission authentication and so on). You can’t implement it in every service.

Summary: We don’t want to duplicate some common logic that supports multiple clients and so on in microservices. We need an API Gateway to provide an intermediate layer to handle differences between service protocols and meet the needs of specific clients.

What is API Gateway

An API gateway is a service in a microservices architecture that provides a shared layer and API for clients to communicate with internal services. API gateways can route requests, transform protocols, aggregate data, and implement shared logic such as authentication and rate limiters.

You can think of the API Gateway as a Gateway to various micro-services.

Our system can have one or more API gateways, depending on the needs of the client. For example, we can provide separate gateways for desktop browsers, mobile applications, and public apis.

The Node.js API Gateway for the front-end team

Because the API Gateway provides support for client applications such as browsers, it can be implemented and managed by the team responsible for front-end applications.

This also means that the API Gateway implementation language should be chosen by the team responsible for the client side. Since JavaScript is the primary language for developing browser applications, Node.js can be a great choice for implementing API Gateways even if your microservices architecture is developed in a different language. Netflix successfully uses the Node.js API Gateway and its Java back end to support a wide range of clients. Learn more.

The utility of API Gateway

We discussed earlier that you can put generic shared logic into the API Gateway, and this section describes its common usage.

Routing and version control

We define the API Gateway as the entry point for microservices. In your API Gateway, you can route requests from clients to specific services. You can even select or change the back-end interface to the version of the server during routing, and the exposed interface can remain the same. You can also aggregate multiple microservices into one point in your API Gateway.

Iterative design

The API Gateway can help you break down bloated applications. Due to the constant iteration of the business, it may not be feasible to rewrite the entire application from scratch as a system with a microservice architecture.

In this case, we can put the proxy or API Gateway ahead of our overall application and implement the new functionality as a microservice, just by ensuring that the API Gateway can route the new interface to the new service while keeping the old interface accessible. Over time, we will migrate these old services into microservices to break down the bloated applications. By designing in small iterations, we were able to smooth the transition from a large whole to a microservice architecture.

certification

Most microservices require authentication to be used. Putting authentication-like shared logic on the API Gateway can make your microservices more focused.

In a microservice architecture, you can place services in a DMZ (demilitarized zone) through network configuration and expose them to clients through the API Gateway. The gateway can also handle multiple authentication methods, for example, cookie – and token-based authentication can be supported.

Data aggregation

In a microservice architecture, clients may require different levels of aggregation of data. In this case, we can use the API Gateway to resolve these dependencies and collect data from multiple services.

Serialization format conversion

This problem occurs when different clients need data in different formats.

Imagine if we used JSON in microservices, but had an XML-only API in a client. Instead of implementing it in each microservice, we could have put the JSON to XML process in the API Gateway.

Protocol conversion

The microservices architecture allows different protocols to be used in order to gain the advantage of using different technologies. However, most clients support only one protocol. In this case, we need to switch the client’s service protocol.

The API Gateway can also serve as a protocol transformation layer between the client and microservices.

As you can see in the picture below, the client only uses HTTP REST to exchange information with various services, while in fact our internal microservices can transfer information based on different specifications and protocols.

Rate control and caching

In addition to authentication, you can also implement rate limiting, caching, and various reliability-related features in the API Gateway.

Overly large API Gateway

When implementing the API Gateway, you should avoid putting non-generic logic, such as domain-specific data transformations, into it.

Services should always have full ownership of their data domains. Building an API Gateway that is too big to compete for control from the service team violates the idea of microservices.

That’s why you should pay attention to data aggregation in your API Gateway — it can be powerful if you know what it does, avoid dealing with business logic in the API Gateway, leave it to whoever it is, and be sure to clarify its role in the overall architecture.

Node.js Gateways

If you want to perform simple operations in the API Gateway, such as routing requests to specific services, you can use a reverse proxy like Nginx. But at some point, you may need to implement logic that is not supported by the general proxy. In this case, you can implement your own API Gateway in Node.js.

In Node.js, you can use HTTP-proxy for simple proxy requests, but you can also use express-Gateway with more functionality.

In the first API Gateway example, we authenticate permissions before its proxy requests the real service.



const express = require('express') 
const httpProxy = require('express-http-proxy')  
const app = express()

const userServiceProxy = httpProxy('https://user-service')

// Authentication
app.use((req, res, next) = > {
  // TODO: my authentication logic  
  next()
})
// Proxy request 
app.get('/users/:userId', (req, res, next) => {    
  userServiceProxy(req, res, next)
}) Copy the code

Another way is for the API Gateway to send a request to the microservice and send the response back to the client:



const express = require('express')  
const request = require('request-promise-native')  
const app = express()
// Resolve: GET /users/me
app.get('/users/me'.async (req, res) => {  
  const userId = req.session.userId
  const uri = `https://user-service/users/${userId}`
  const user = await request(uri)
  res.json(user)
})Copy the code

Conclusion:

The API Gateway provides an intermediate layer to coordinate client and microservice architectures. It helps us fulfill the single responsibility principle, keeping our app or service focused on one thing. You can put generic logic in the API Gateway, but you should also be careful not to overuse the API Gateway.