Skip to content
← API Gateway · beginner · 11 min · 01 / 07

What Is an API Gateway

The single entry point in front of your services — routing, auth, rate limiting, and transformation without touching your backends.

api gatewayreverse proxyroutingcross-cutting concerns

Real-World Analogy

A hotel concierge — every guest request goes through them. They verify you’re a guest (auth), direct you to the right department (routing), won’t let one guest monopolize staff time (rate limiting), and handle translation if needed (transformation). The departments never deal with unvetted guests directly.

The Problem It Solves

Without a gateway, every client talks directly to every service:

Mobile app  ──→ User Service :3001
            ──→ Order Service :3002
            ──→ Product Service :3003
            ──→ Payment Service :3004

Every service must independently implement auth, rate limiting, logging, CORS, SSL termination. When the auth logic changes, you update ten services. When you add a new service, the mobile app ships a new build to hit the new URL.

With a gateway:

Mobile app  ──→ API Gateway :443
                    ├──→ User Service :3001
                    ├──→ Order Service :3002
                    ├──→ Product Service :3003
                    └──→ Payment Service :3004

The gateway owns cross-cutting concerns. Services handle business logic only.

What a Gateway Does

Routing — map incoming paths to backend services:

GET  /users/*        → user-service
GET  /orders/*       → order-service
POST /payments/*     → payment-service

Authentication — validate JWT/API key before the request reaches any service. Services trust the gateway and don’t re-verify.

Rate limiting — cap requests per client, per route, per plan tier.

SSL termination — accept HTTPS from clients, forward HTTP internally. Services don’t need certificates.

Request/response transformation — add headers, strip fields, reshape payloads.

Load balancing — distribute traffic across multiple instances of each service.

Observability — one place to collect access logs, trace IDs, latency metrics for all traffic.

Gateway vs Reverse Proxy vs Load Balancer

These terms overlap but have distinct meanings:

Reverse ProxyLoad BalancerAPI Gateway
Routes byURL/hostConnectionURL + headers + method
AuthNoNoYes
Rate limitingNoNoYes
Transforms payloadsRarelyNoYes
Examplesnginx, CaddyHAProxy, AWS NLBKong, AWS API Gateway, Traefik

A gateway is a reverse proxy with application-layer awareness. Many tools blur these lines — nginx can do gateway work with plugins, Traefik is a proxy with gateway features built in.

Self-Hosted vs Managed

Self-hosted: Kong, Traefik, Envoy, nginx + Lua. You run the gateway, own the config, pay compute costs. More control, more ops burden.

Managed: AWS API Gateway, Google Cloud Endpoints, Azure API Management, Cloudflare API Gateway. Fully managed, per-request pricing, opinionated configuration.

When managed wins: Early-stage, small team, AWS-native stack. You get auth, rate limiting, and a dashboard without running anything.

When self-hosted wins: High traffic (managed gateways get expensive fast), non-AWS stack, need custom plugins, strict latency requirements.

A Minimal Gateway in Node.js

Before reaching for Kong or AWS, understand what a gateway actually is — a reverse proxy with middleware:

import http from 'http';
import httpProxy from 'http-proxy';

const proxy = httpProxy.createProxyServer({});

const routes: Record<string, string> = {
  '/users':    'http://user-service:3001',
  '/orders':   'http://order-service:3002',
  '/products': 'http://product-service:3003',
};

function matchRoute(path: string): string | null {
  for (const [prefix, target] of Object.entries(routes)) {
    if (path.startsWith(prefix)) return target;
  }
  return null;
}

const gateway = http.createServer((req, res) => {
  // 1. Auth
  const token = req.headers['authorization']?.split(' ')[1];
  if (!verifyJWT(token)) {
    res.writeHead(401, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify({ error: 'Unauthorized' }));
    return;
  }

  // 2. Rate limiting (simplified)
  const clientIp = req.socket.remoteAddress!;
  if (isRateLimited(clientIp)) {
    res.writeHead(429, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify({ error: 'Too Many Requests' }));
    return;
  }

  // 3. Route
  const target = matchRoute(req.url ?? '/');
  if (!target) {
    res.writeHead(404);
    res.end(JSON.stringify({ error: 'Not Found' }));
    return;
  }

  // 4. Add internal headers
  req.headers['x-request-id'] = crypto.randomUUID();
  req.headers['x-forwarded-for'] = clientIp;

  // 5. Proxy
  proxy.web(req, res, { target });
});

gateway.listen(3000);

Production gateways are this loop — vastly optimized and hardened.