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 (0)