Understanding API Gateways and Their Role in Microservice Architectures
This article explains what an API gateway is, why it is essential in microservice architectures, and how it handles cross‑cutting concerns such as authentication, transport security, load balancing, request routing, dependency resolution, and data transformation, illustrated with a simple Node.js gateway example and code snippets.
In this article we discuss API gateways and how they help solve important problems in microservice‑based architectures, building on the first article of the series.
What Is an API Gateway and Why Use It?
API gateways sit in the upper layer of the software stack and address shared cross‑cutting concerns across services, such as authentication, transport security, load balancing, request routing (including fault tolerance and service discovery), dependency resolution, and transport transformation.
Authentication
Most gateways perform authentication for each request, routing the request to the appropriate microservice or returning an error. They often add authentication information to the request before forwarding it, enabling downstream services to implement user‑specific logic.
Transport Security
Gateways act as a single entry point for public APIs, handling transport security (e.g., SSL termination) before forwarding requests to internal services over non‑SSL connections.
Load Balancing
Under high load, a gateway can distribute requests among microservice instances based on custom logic, taking into account each service’s scaling limits.
Request Routing
Gateways provide custom routing logic, cooperating with service registration/discovery mechanisms to dynamically route requests, support failover to backup services, and enable flexible request handling.
Dependency Resolution
Gateways can present a virtual endpoint that aggregates calls to many internal services, reducing the chatter between microservices.
Transport Transformation
Because microservices may use different data formats, gateways perform necessary transformations so that clients can communicate with the underlying services.
API Gateway Example (Node.js)
The following simple Node.js gateway handles HTTP requests, performs authentication with JWT, and forwards requests to internal endpoints while applying required transformations.
/*
* Simple login: returns a JWT if login data is valid.
*/
function doLogin(req, res) {
getData(req).then(function(data) {
try {
var loginData = JSON.parse(data);
User.findOne({ username: loginData.username }, function(err, user) {
if (err) { logger.error(err); send401(res); return; }
if (user.password === loginData.password) {
var token = jwt.sign({ jti: uuid.v4(), roles: user.roles }, secretKey, {
subject: user.username,
issuer: issuerStr
});
res.writeHeader(200, { 'Content-Length': token.length, 'Content-Type': "text/plain" });
res.write(token);
res.end();
} else {
send401(res);
}
}, 'users');
} catch (err) {
logger.error(err);
send401(res);
}
}, function(err) {
logger.error(err);
send401(res);
});
}
/* Authentication validation using JWT. Strategy: find existing user. */
function validateAuth(data, callback) {
if (!data) { callback(null); return; }
data = data.split(" ");
if (data[0] !== "Bearer" || !data[1]) { callback(null); return; }
var token = data[1];
try {
var payload = jwt.verify(token, secretKey);
if (!payload.jti || revokedTokens[payload.jti]) {
logger.debug('Revoked token, access denied: ' + payload.jti);
callback(null);
} else {
callback({ jwt: payload });
}
} catch (err) {
logger.error(err);
callback(null);
}
}Transport Security
Transport security is handled via TLS; public requests first hit a reverse Nginx proxy with a sample certificate.
Dynamic Routing, Data Aggregation, and Fault Handling
Requests are dynamically scheduled based on configuration stored in a database, supporting both HTTP and AMQP. The gateway can aggregate responses from multiple internal services into a single JSON payload.
/*
* Parses the request and dispatches multiple concurrent requests to each internal endpoint.
* Results are aggregated and returned.
*/
function serviceDispatch(req, res) {
var parsedUrl = url.parse(req.url);
Service.findOne({ url: parsedUrl.pathname }, function(err, service) {
if (err) { logger.error(err); send500(res); return; }
var authorized = roleCheck(req.context.authPayload.jwt, service);
if (!authorized) { send401(res); return; }
var promises = [];
service.endpoints.forEach(function(endpoint) {
logger.debug(sprintf('Dispatching request from public endpoint %s to internal endpoint %s (%s)', req.url, endpoint.url, endpoint.type));
switch (endpoint.type) {
case 'http-get':
case 'http-post':
promises.push(httpPromise(req, endpoint.url, endpoint.type === 'http-get'));
break;
case 'amqp':
promises.push(amqpPromise(req, endpoint.url));
break;
default:
logger.error('Unknown endpoint type: ' + endpoint.type);
}
});
Q.allSettled(promises).then(function(results) {
var responseData = {};
results.forEach(function(result) {
if (result.state === 'fulfilled') {
responseData = _.extend(responseData, result.value);
} else {
logger.error(result.reason.message);
}
});
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify(responseData));
});
}, 'services');
}Role Check
var User = userDb.model('User', new mongoose.Schema({ username: String, password: String, roles: [String] }));
var Service = servicesDb.model('Service', new mongoose.Schema({
name: String,
url: String,
endpoints: [new mongoose.Schema({ type: String, url: String })],
authorizedRoles: [String]
}));
function roleCheck(jwt_, service) {
var intersection = _.intersection(jwt_.roles, service.authorizedRoles);
return intersection.length === service.authorizedRoles.length;
}Logging
Logging is centralized: all logs are published to the console and an internal message bus, where other services can react.
Conclusion
API gateways are a vital component of any microservice‑based architecture, providing a convenient, unified way to handle cross‑cutting concerns such as authentication, load balancing, dependency resolution, data transformation, and dynamic request routing, allowing individual microservices to focus on their core responsibilities and accelerate development.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Architects Research Society
A daily treasure trove for architects, expanding your view and depth. We share enterprise, business, application, data, technology, and security architecture, discuss frameworks, planning, governance, standards, and implementation, and explore emerging styles such as microservices, event‑driven, micro‑frontend, big data, data warehousing, IoT, and AI architecture.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
