Understanding API Gateways: Roles, Implementation, and a Node.js Example

This article explains what API gateways are, why they are essential in micro‑service architectures, outlines the cross‑cutting concerns they address such as authentication, transport security, load balancing, request routing, dependency resolution and data transformation, and provides a practical Node.js implementation with code samples.

Architects Research Society
Architects Research Society
Architects Research Society
Understanding API Gateways: Roles, Implementation, and a Node.js Example

In this part of the micro‑service series we discuss API gateways and how they help solve important problems in a micro‑service architecture, building on the issues described in the first article.

What Is an API Gateway and Why Use It?

All service‑based architectures share several cross‑cutting concerns, and micro‑services are no exception. Because micro‑services are developed in isolation, higher‑level layers of the software stack handle these concerns, and the API gateway is one such layer.

Authentication

Transport security

Load balancing

Request routing (including fault tolerance and service discovery)

Dependency resolution

Transport transformation

Authentication

Most gateways perform some form of authentication for each request (or a batch of requests). Based on service‑specific rules the gateway either forwards the request to the appropriate micro‑service or returns an error code. When forwarding, the gateway often adds authentication information to the request so that downstream services can apply user‑specific logic.

Security

Many gateways act as a single entry point for public APIs. In this role they handle transport security, for example by terminating SSL: a secure TLS connection is established between the client and the gateway, and the gateway forwards the request to internal services over a non‑SSL channel.

“Many gateways serve as a single entry point for public APIs.”

Load Balancing

Under high load the gateway can distribute requests among micro‑service instances according to custom logic, taking into account each service’s scaling limits. For services that run multiple instances behind different internal endpoints, the gateway can route requests to those endpoints or even trigger dynamic instantiation.

Request Routing

The gateway can provide custom routing logic even under normal load. In large architectures, internal endpoints are added or removed as teams create or retire micro‑services. The gateway can cooperate with a service‑registry/discovery mechanism or a database that describes how each request should be dispatched, enabling flexible routing, fail‑over to backup services, and graceful handling of service failures.

Dependency Resolution

Because micro‑services often need to call many other services to accomplish a task, the gateway can expose “virtual” endpoints that internally route to multiple micro‑services, reducing chatter and improving performance.

Transport Transformation

Micro‑services may return data in formats that are inconvenient for clients. The gateway performs the necessary transformations so that clients can interact with the backend services transparently.

API Gateway Example

Below is a simple Node.js gateway that handles HTTP requests, forwards them to appropriate internal endpoints, and performs required transport transformations. It addresses the concerns listed above.

Authentication (Example)

The example uses JWT for authentication. A single endpoint (/login) validates credentials stored in a MongoDB database and issues a token whose access is limited by role.

/*
 * 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);
  }
}

Disclaimer: The code shown is for illustration only and is not production‑ready. Do not copy‑paste blindly.

Transport Security

Transport security is handled via TLS: all public requests first hit a reverse Nginx proxy with a sample certificate before being forwarded internally.

Load Balancing

Load balancing is performed by Nginx; see the example configuration for details.

Dynamic Routing, Data Aggregation and Fault Handling

Requests are dynamically scheduled based on configuration stored in a database, supporting both HTTP and AMQP protocols. The gateway can aggregate responses from multiple internal services into a single JSON payload, a pattern used by Netflix for performance and by Falcor for easy multi‑source data fetching.

Failures of internal requests are handled by logging the error and returning reduced information to the client.

/*
 * 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; }
    // Fanout all requests to all related endpoints.
    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;
}

Transport and Data Transformation

The gateway performs transport transformation to convert between HTTP and AMQP requests.

Logging

Logging is centralized: all logs are published to the console and an internal message bus, where other services can react.

Get the full source code.

Narrative: How Webtask and Auth0 Implement These Patterns

Webtasks are themselves micro‑services that run behind the gateway. The gateway handles authentication, dynamic routing, and centralized logging for them.

Authentication: Auth0 issues tokens; webtasks validate those tokens, establishing a trust relationship.

Real‑time logging: Webtasks implement a stateless, elastic ZeroMQ architecture that runs across the cluster.

Dynamic routing: A custom Node.js proxy uses CoreOS etcd as a pub‑sub mechanism to route webtasks appropriately.

Conclusion

API gateways are a crucial component of any micro‑service‑based architecture. They provide a convenient, uniform way to handle cross‑cutting concerns such as authentication, load balancing, dependency resolution, data transformation, and dynamic request routing, allowing individual micro‑services to focus on their specific business logic and accelerate development.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

load balancingapi-gatewayAuthenticationTransport Security
Architects Research Society
Written by

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.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.