Post

Epoch 8: API Gateway (Custom-built with ExpressJS)

The API Gateway acts as the single entry point for all client requests. It routes requests to appropriate microservices, handles authentication (JWT), and can perform tasks like CORS handling, request logging, and rate limiting.

Epoch 8: API Gateway (Custom-built with ExpressJS)

Objectives

  • Understand the API Gateway pattern.
  • Build a basic gateway using ExpressJS.
  • Route traffic to backend microservices.
  • Forward client JWT tokens for downstream verification.
  • Handle CORS and request logging centrally.

1. Initialize the API Gateway

mkdir api-gateway
cd api-gateway
npm init -y
npm install express http-proxy-middleware dotenv cors morgan

2. Folder Structure

1
2
3
4
5
6
7
api-gateway/
├── src/
│   └── index.js
│   └── routes/
│       └── proxyRoutes.js
├── .env
├── package.json

Add JWT_SECRET to .env of each service.

3. Setup Environment Variables

PORT=3000

USER_SERVICE_URL=http://user-service:3001
PRODUCT_SERVICE_URL=http://product-service:3002
ORDER_SERVICE_URL=http://order-service:3003
NOTIFICATION_SERVICE_URL=http://notification-service:3004

4. Proxy Configuration

In src/routes/proxyRoutes.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import { createProxyMiddleware } from 'http-proxy-middleware';
import dotenv from 'dotenv';

dotenv.config();

export const userProxy = createProxyMiddleware('/users', {
  target: process.env.USER_SERVICE_URL,
  changeOrigin: true,
  pathRewrite: { '^/users': '' },
});

export const productProxy = createProxyMiddleware('/products', {
  target: process.env.PRODUCT_SERVICE_URL,
  changeOrigin: true,
  pathRewrite: { '^/products': '' },
});

export const orderProxy = createProxyMiddleware('/orders', {
  target: process.env.ORDER_SERVICE_URL,
  changeOrigin: true,
  pathRewrite: { '^/orders': '' },
});

export const notificationProxy = createProxyMiddleware('/notify', {
  target: process.env.NOTIFICATION_SERVICE_URL,
  changeOrigin: true,
  pathRewrite: { '^/notify': '' },
});

5. Main Server Logic

In src/index.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import express from 'express';
import cors from 'cors';
import morgan from 'morgan';
import dotenv from 'dotenv';

import {
  userProxy,
  productProxy,
  orderProxy,
  notificationProxy,
} from './routes/proxyRoutes.js';

dotenv.config();

const app = express();
const PORT = process.env.PORT || 3000;

// Middleware
app.use(cors());
app.use(morgan('dev'));

// Proxies
app.use('/users', userProxy);
app.use('/products', productProxy);
app.use('/orders', orderProxy);
app.use('/notify', notificationProxy);

// Root
app.get('/', (req, res) => {
  res.send('API Gateway is running');
});

app.listen(PORT, () => {
  console.log(`API Gateway running at http://localhost:${PORT}`);
});

6. Docker Integration

Update docker-compose.yml:

1
2
3
4
5
6
7
8
9
  api-gateway:
    build: ./api-gateway
    ports:
      - "3000:3000"
    depends_on:
      - user-service
      - product-service
      - order-service
      - notification-service

Add Dockerfile:

1
2
3
4
5
FROM node:18
WORKDIR /app
COPY . .
RUN npm install
CMD ["node", "src/index.js"]

7. Test Gateway Routing

  • GET http://localhost:3000/users/me → proxies to user-service
  • POST http://localhost:3000/products → proxies to product-service
  • POST http://localhost:3000/notify → proxies to notification-service

Optional: JWT Middleware at Gateway

Add token verification at the gateway like this:

  • middleware/auth.js ```js import jwt from ‘jsonwebtoken’;

export const gatewayAuth = (req, res, next) => { const token = req.headers.authorization?.split(“ “)[1]; if (!token) return res.status(401).json({ error: ‘Missing token’ });

try { req.user = jwt.verify(token, process.env.JWT_SECRET); next(); } catch { return res.status(403).json({ error: ‘Invalid token’ }); } };

1
2
3
4
Then use:
```js
app.use('/products', gatewayAuth, productProxy);
This post is licensed under CC BY 4.0 by the author.