!NB: Copyright Somendradev
As your app scales, it often evolves from a monolith into a set of microservices — each responsible for a specific business function. That’s great for scaling teams and codebases, but it introduces a big problem:
How do you give clients a single, seamless entry point while keeping your microservices loosely coupled?
The answer is an API Gateway.
In this post, we’ll break down what an API Gateway is, why you need one, and how to build a Node.js-powered API Gateway with real examples.
An API Gateway acts as the front door to your entire system:
- Clients (mobile apps, web apps) send requests only to the gateway.
- The gateway routes requests to the right microservices.
- It can handle auth, rate limiting, caching, logging, request/response transformations, and load balancing.
Think of it like an air traffic controller for your microservices.
Without one, every client would need to know:
- All your microservice URLs
- Their authentication methods
- Request and response formats
That’s a maintenance nightmare. An API Gateway centralizes everything, making your architecture easier to maintain and scale.
Key benefits:
✅ Single entry point for clients
✅ Centralized security & logging
✅ Easy scaling and service discovery
✅ Request/response shaping without touching microservices
We’ll build a simple API Gateway with:
- Node.js + Express.js (lightweight and fast)
- http-proxy-middleware (for routing requests)
- JWT Authentication (optional security layer)
First, initialize a new project:
mkdir api-gateway
cd api-gateway
npm init -y
npm install express http-proxy-middleware jsonwebtoken dotenv// index.js
const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');
require('dotenv').config();
const app = express();
// Body parser
app.use(express.json());
// Simple health route
app.get('/health', (req, res) => res.json({ status: 'API Gateway Running' }));
// Start server
app.listen(3000, () => {
console.log('API Gateway listening on port 3000');
});Run node index.js and visit http://localhost:3000/health to confirm it’s working.
Let’s assume you have these microservices running:
- User Service:
[http://localhost:4001](http://localhost:4001/) - Product Service:
[http://localhost:4002](http://localhost:4002/)
We’ll set up proxy routes:
// Proxy routes
app.use('/users', createProxyMiddleware({
target: 'http://localhost:4001',
changeOrigin: true,
pathRewrite: { '^/users': '' }
}));
app.use('/products', createProxyMiddleware({
target: 'http://localhost:4002',
changeOrigin: true,
pathRewrite: { '^/products': '' }
}));Now:
GET /users/list→ forwards to[http://localhost:4001/list](http://localhost:4001/list)GET /products/123→ forwards to[http://localhost:4002/123](http://localhost:4002/123)
Centralize authentication at the gateway:
const jwt = require('jsonwebtoken');
// Middleware to verify JWT
function authenticateToken(req, res, next) {
const token = req.headers\['authorization'\]?.split(' ')\[1\];
if (!token) return res.status(401).json({ message: 'Unauthorized' });
jwt.verify(token, process.env.JWT\_SECRET, (err, user) => {
if (err) return res.status(403).json({ message: 'Forbidden' });
req.user = user;
next();
});
}
// Apply auth for protected routes
app.use('/products', authenticateToken);In production, logging requests at the gateway helps with monitoring and debugging.
app.use((req, res, next) => {
console.log(\`\[${new Date().toISOString()}\] ${req.method} ${req.originalUrl}\`);
next();
});- Rate Limiting: Use
express-rate-limitto throttle requests. - Caching: Add Redis or in-memory caching to speed up responses.
- Service Discovery: Dynamically register and deregister services with Consul or etcd.
- Circuit Breakers: Prevent cascading failures using
opossum.
How the Architecture Looks
+---------------------+
Client --> | API Gateway | --> User Service
| (Auth, Logging, | --> Product Service
| Rate Limiting) | --> Other Services
+---------------------+
Imagine a shopping platform:
- Frontend calls
/products→ Gateway routes it to Product Service. - Frontend calls
/users/orders→ Gateway routes to Order Service. - Gateway checks JWT token → Blocks unauthenticated users.
- Gateway logs all activity to ELK stack for analytics.
This setup ensures your frontend never has to know the URLs of your services.
- An API Gateway is critical for microservice-based apps.
- Node.js + Express +
http-proxy-middlewareis a great starting point. - You can easily add auth, logging, caching, rate limiting, and service discovery as your system grows.
Start simple, then evolve your gateway into a feature-packed traffic manager for your microservices.