DEV Community

Yogesh Prasad
Yogesh Prasad

Posted on

NestJS Expert Series – Part 5: API Gateway and Service Communication

Welcome back to the NestJS Expert Series! 👋
In Part 4, we built scalable microservices with RabbitMQ.
Now, it’s time to take the next step — integrating them with an API Gateway and service-to-service communication.

🚀 Why Use an API Gateway?

When your app grows into multiple microservices (Auth, Users, Orders, Payments, etc.), clients shouldn’t need to know where each service lives.

Instead, the API Gateway acts as a single entry point — handling:

Authentication

Routing requests to the right microservice

Response aggregation

Rate limiting, caching, logging

This is the same principle used by Netflix, Uber, and Amazon for their distributed architectures.

⚙️ Step 1 – Setup a New API Gateway Project

Let’s create a separate NestJS project to act as the gateway:

nest new api-gateway

Then, install the microservice package:

npm i @nestjs/microservices

🛠 Step 2 – Connect the Gateway to Microservices

In your app.module.ts of the API Gateway:

import { Module } from '@nestjs/common';
import { ClientsModule, Transport } from '@nestjs/microservices';
import { GatewayController } from './gateway.controller';

@Module({
  imports: [
    ClientsModule.register([
      {
        name: 'AUTH_SERVICE',
        transport: Transport.TCP,
        options: { host: 'localhost', port: 3001 },
      },
      {
        name: 'USER_SERVICE',
        transport: Transport.TCP,
        options: { host: 'localhost', port: 3002 },
      },
    ]),
  ],
  controllers: [GatewayController],
})
export class AppModule {}
Enter fullscreen mode Exit fullscreen mode

This defines two microservice connections:

AUTH_SERVICE (for authentication)

USER_SERVICE (for user-related operations)

🧩 Step 3 – Build the Gateway Controller

gateway.controller.ts:

import { Controller, Get, Inject, Post, Body } from '@nestjs/common';
import { ClientProxy } from '@nestjs/microservices';

@Controller('gateway')
export class GatewayController {
  constructor(
    @Inject('AUTH_SERVICE') private authClient: ClientProxy,
    @Inject('USER_SERVICE') private userClient: ClientProxy,
  ) {}

  @Post('login')
  async login(@Body() credentials: any) {
    return this.authClient.send({ cmd: 'login' }, credentials);
  }

  @Get('users')
  async getUsers() {
    return this.userClient.send({ cmd: 'get_users' }, {});
  }
}

Enter fullscreen mode Exit fullscreen mode

✅ Here:

The gateway sends messages to different microservices via TCP transport.

Each microservice listens for specific message patterns and responds.

🎧 Step 4 – Listening in the Microservice
Example from user-service:

import { Controller } from '@nestjs/common';
import { MessagePattern } from '@nestjs/microservices';

@Controller()
export class UserController {
  @MessagePattern({ cmd: 'get_users' })
  getUsers() {
    return [
      { id: 1, name: 'Yogesh' },
      { id: 2, name: 'Aditi' },
    ];
  }
}


Enter fullscreen mode Exit fullscreen mode

Now, when the gateway sends { cmd: 'get_users' }, this microservice responds with a list of users.

🧠 Step 5 – Add Authentication Middleware

To protect routes at the gateway level:

import { Injectable, NestMiddleware } from '@nestjs/common';
import * as jwt from 'jsonwebtoken';

@Injectable()
export class AuthMiddleware implements NestMiddleware {
  use(req: any, res: any, next: () => void) {
    const token = req.headers['authorization']?.split(' ')[1];
    if (!token) return res.status(401).json({ message: 'Unauthorized' });

    try {
      const decoded = jwt.verify(token, 'SECRET_KEY');
      req.user = decoded;
      next();
    } catch {
      return res.status(401).json({ message: 'Invalid token' });
    }
  }
}

Enter fullscreen mode Exit fullscreen mode

This ensures centralized authentication — one verification at the gateway before forwarding requests to microservices.

💡 Step 6 – Service Discovery (Optional)
For dynamic scaling, you can integrate Consul or Eureka to allow automatic service registration and discovery.
This prevents hardcoding service URLs and enables horizontal scaling easily.

🧭 Summary

✅ Implemented a central API Gateway
✅ Connected multiple microservices using TCP transport
✅ Added authentication middleware
✅ Laid the foundation for distributed, secure communication

🔮 Coming Up Next (Part 6)

In Part 6, we’ll take it even further:

🔧 “Monitoring, Logging, and Observability in NestJS Microservices.”

You’ll learn how to use Winston, Prometheus, and Grafana to track, debug, and optimize microservice performance.

Top comments (1)

Collapse
 
sangwoo_rhie profile image
Sangwoo Lee

great content!