
API Gateway with NestJS: Handle Multi-Service Routing, Authentication, and Rate Limiting
API Gateway with NestJS: Handle Multi-Service Routing, Authentication, and Rate Limiting
Learn how to build a powerful API Gateway using NestJS to route requests between microservices, apply authentication, and manage rate limiting. A practical, real-world guide for scalable microservice architecture.
๐ฆ API Gateway with NestJS: Handle Multi-Service Routing, Auth, and Rate Limiting
But when services grow, we need a single entry point to:
- Route requests to the right service
- Authenticate users
- Apply rate limits and security rules
- Aggregate responses
Thatโs where an API Gateway comes in.
In this hands-on guide, Iโll show you how to build a robust API Gateway with NestJS, using:
- HTTP Proxying for routing
- Guards for Authentication
- Rate Limiting for abuse protection
- Support for multiple microservices (HTTP & TCP)
Letโs build something awesome. ๐
๐ง What is an API Gateway?
An API Gateway is a single layer between your frontend and multiple backend services. It accepts requests, validates them, and forwards them to the correct microservice.
๐ Example Use Case
Frontend โ API Gateway โ Auth Service โ Users Service โ Orders Service
Instead of calling each service directly, the frontend only communicates with the gateway, simplifying architecture and allowing centralized control.
๐๏ธ Project Setup
Start by creating a new NestJS project for the gateway:
npx @nestjs/cli new api-gateway cd api-gateway
Install the needed libraries:
npm install --save axios @nestjs/throttler
Weโll use:
axios
for HTTP proxying@nestjs/throttler
for rate limiting
๐๏ธ Folder Structure (Simplified)
src/ โโโ main.ts โโโ gateway.controller.ts โโโ gateway.service.ts โโโ auth.guard.ts โโโ throttler.guard.ts โโโ app.module.ts
๐ 1. Proxy Requests to Microservices
Letโs say we want to route:
/auth/login
โ Auth Service/users/profile
โ Users Service
๐งฉ gateway.service.ts
import { Injectable } from '@nestjs/common'; import axios, { AxiosRequestConfig } from 'axios'; @Injectable() export class GatewayService { private services = { auth: 'http://localhost:3001', users: 'http://localhost:3002', }; async forward(service: 'auth' | 'users', path: string, method: string, body: any, headers: any) { const url = `${this.services[service]}${path}`; const config: AxiosRequestConfig = { method, url, headers, data: body, }; const res = await axios(config); return res.data; } }
๐ฎ 2. Create a Gateway Controller
import { Controller, Req, Res, All, UseGuards, HttpException, HttpStatus, } from '@nestjs/common'; import { Request, Response } from 'express'; import { GatewayService } from './gateway.service'; import { AuthGuard } from './auth.guard'; import { ThrottlerGuard } from './throttler.guard'; @Controller() export class GatewayController { constructor(private gatewayService: GatewayService) {} @All('*') @UseGuards(ThrottlerGuard, AuthGuard) async proxy(@Req() req: Request, @Res() res: Response) { try { const [_, service, ...restPath] = req.path.split('/'); const path = '/' + restPath.join('/'); const data = await this.gatewayService.forward( service as 'auth' | 'users', path, req.method, req.body, req.headers, ); res.json(data); } catch (error) { throw new HttpException(error?.response?.data || 'Service Error', HttpStatus.BAD_GATEWAY); } } }
This intercepts all incoming requests (@All('*')
) and dynamically proxies them to the appropriate service based on the path.
๐ 3. Add an Authentication Guard
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common'; @Injectable() export class AuthGuard implements CanActivate { canActivate(context: ExecutionContext): boolean { const req = context.switchToHttp().getRequest(); const auth = req.headers['authorization']; // You could validate a token here, or forward it to the auth service return !!auth; // For demo purposes, allow if Authorization header exists } }
In production, you'd verify JWT tokens or forward the token to the auth
service to validate.
๐ง 4. Apply Rate Limiting (Per IP)
import { Injectable } from '@nestjs/common'; import { ThrottlerGuard as BaseThrottlerGuard, ThrottlerModule, } from '@nestjs/throttler'; @Injectable() export class ThrottlerGuard extends BaseThrottlerGuard {}
In your app.module.ts
:
import { Module } from '@nestjs/common'; import { ThrottlerModule } from '@nestjs/throttler'; import { GatewayController } from './gateway.controller'; import { GatewayService } from './gateway.service'; import { AuthGuard } from './auth.guard'; import { ThrottlerGuard } from './throttler.guard'; @Module({ imports: [ ThrottlerModule.forRoot({ ttl: 60, // 1 minute limit: 10, // 10 requests per minute per IP }), ], controllers: [GatewayController], providers: [GatewayService, AuthGuard, ThrottlerGuard], }) export class AppModule {}
๐ 5. Bonus: Support for TCP Microservices
If your microservices use TCP instead of HTTP, you can use NestJSโs ClientProxy
.
But thatโs a topic for another post ๐ (let me know if you want me to write that next!)
โ Final Thoughts
An API Gateway is essential for any production-level microservices system.
By combining:
- Dynamic routing
- Centralized authentication
- Rate limiting & security
- Flexible microservice forwarding
โฆyou gain full control, scalability, and flexibility across your backend.
NestJS makes it surprisingly clean and powerful to implement these ideas.
๐ Bonus Resources
๐ Was this helpful?
If you found this post useful, share it with someone building with microservices or NestJS.