Understanding API Gateways and Their Role in Microservice Architectures
This article explains what API gateways are, why they are essential in microservice architectures, and how they address cross‑cutting concerns such as authentication, transport security, load balancing, request routing, dependency resolution, and data transformation, illustrated with a Node.js example.
In this part of the microservice series we discuss API gateways and how they solve several important problems inherent to microservice‑based architectures, building on the issues described in the first article.
What Is an API Gateway and Why Use It?
API gateways sit in the upper layer of the software stack and handle 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 per request (or per batch of requests) and, based on service‑specific rules, either route the request to the appropriate microservice or return an error. They often add authentication information to the request before forwarding it, enabling downstream services to implement user‑specific logic.
Security
Gateways commonly act as the single entry point for public APIs, handling transport security (e.g., SSL termination) before forwarding requests to internal services over non‑SSL connections.
“Many gateways serve as the single entry point for public APIs.”
Load Balancing
Under high load, gateways can distribute requests among microservice instances according to custom logic, taking into account each service’s scaling limits and dynamically instantiating additional endpoints when needed.
Request Routing
Gateways provide custom routing logic that works with service registration/discovery mechanisms, allowing dynamic addition or removal of internal endpoints, routing failed services to backups, and ensuring requests complete rather than failing outright.
Dependency Resolution
Because microservices often need to call many other services to accomplish a task, gateways can present a “virtual” endpoint that aggregates multiple internal calls, simplifying client interaction.
Transport Transformation
Microservices may return data in formats inconvenient for clients; gateways perform necessary transformations so clients can communicate seamlessly with downstream services.
API Gateway Example
Below is a simple Node.js gateway that handles HTTP requests, forwards them to appropriate internal endpoints, and performs required transformations. It demonstrates authentication, load balancing, dynamic routing, and logging.
Authentication (JWT)
Login endpoint uses JWT; user details are stored in MongoDB and access is role‑restricted.
/*
* 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); }
}Dynamic Dispatch, Data Aggregation, and Fault Handling
The gateway can dynamically dispatch requests to multiple internal endpoints (HTTP or AMQP), aggregate JSON responses, and log errors while returning minimal information on failures.
/*
* 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;
}Conclusion
API gateways are a vital component of any microservice‑based architecture, handling cross‑cutting concerns such as authentication, load balancing, dependency resolution, data transformation, and dynamic request routing, thereby 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.
