Building Microservices in NestJS (TCP, Redis, gRPC)

Microservices architecture is a popular pattern for designing scalable, flexible, and maintainable systems. NestJS, with its built-in support for multiple transport layers, makes it easy to implement microservices in a variety of communication patterns. In this module, we will explore how to build microservices in NestJS using three popular transport mechanisms: TCP, Redis, and gRPC.

We will cover:

  • How to set up a TCP microservice in NestJS.
  • Using Redis for message-based communication between services.
  • Implementing gRPC for efficient and reliable communication.

Table of Contents

  1. What are Microservices?
  2. Setting Up a TCP Microservice
  3. Building a Redis Microservice
  4. Creating a gRPC Microservice
  5. Best Practices for Building Microservices in NestJS
  6. Conclusion

What are Microservices?

A microservices architecture breaks down a system into a collection of loosely coupled, independently deployable services. Each service in this architecture typically performs a single function, handles its own data, and communicates with other services via APIs or messaging.

NestJS simplifies the development of microservices by providing native support for several communication patterns, including TCP, Redis, and gRPC. These transport layers can be used to create scalable, fault-tolerant systems that are easier to maintain and extend.


Setting Up a TCP Microservice

Installing Dependencies

NestJS supports TCP out of the box via the @nestjs/microservices package, which simplifies setting up a TCP server and client.

bashCopyEditnpm install @nestjs/microservices

Creating the TCP Service

Let’s create a simple TCP-based microservice where we send a message to the microservice, and it responds with a greeting.

microservice.module.ts

tsCopyEditimport { Module } from '@nestjs/common';
import { MicroserviceController } from './microservice.controller';

@Module({
  controllers: [MicroserviceController],
})
export class MicroserviceModule {}

microservice.controller.ts

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

@Controller()
export class MicroserviceController {
  @MessagePattern('greet')
  greet(name: string): string {
    return `Hello, ${name}!`;
  }
}

main.ts (Microservice Setup)

tsCopyEditimport { NestFactory } from '@nestjs/core';
import { MicroserviceModule } from './microservice.module';
import { Transport } from '@nestjs/microservices';

async function bootstrap() {
  const app = await NestFactory.createMicroservice(MicroserviceModule, {
    transport: Transport.TCP,
    options: {
      host: '127.0.0.1',
      port: 3001,
    },
  });
  await app.listen();
}

bootstrap();

In this setup:

  • @MessagePattern is used to listen for a message from the TCP client.
  • The greet method handles the incoming message and responds with a personalized greeting.

Building a Redis Microservice

Setting Up Redis

Before setting up the Redis microservice, make sure Redis is installed and running on your machine. You can download Redis from here, or use a Redis instance on a cloud provider like RedisLabs.

Redis Microservice Implementation

In this example, we’ll use Redis as a message broker between microservices.

redis.module.ts

tsCopyEditimport { Module } from '@nestjs/common';
import { RedisController } from './redis.controller';

@Module({
  controllers: [RedisController],
})
export class RedisModule {}

redis.controller.ts

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

@Controller()
export class RedisController {
  @MessagePattern('redis_message')
  handleMessage(message: string): string {
    return `Received message from Redis: ${message}`;
  }
}

main.ts (Redis Microservice Setup)

tsCopyEditimport { NestFactory } from '@nestjs/core';
import { RedisModule } from './redis.module';
import { Transport } from '@nestjs/microservices';

async function bootstrap() {
  const app = await NestFactory.createMicroservice(RedisModule, {
    transport: Transport.REDIS,
    options: {
      url: 'redis://localhost:6379', // Redis server URL
    },
  });
  await app.listen();
}

bootstrap();

Here:

  • We use @MessagePattern to listen for messages sent via Redis.
  • Redis is configured as the transport layer, and messages are sent to the Redis server at localhost:6379.

Creating a gRPC Microservice

Setting Up gRPC

To use gRPC in NestJS, we need the gRPC and protobufjs dependencies:

bashCopyEditnpm install @nestjs/microservices grpc @grpc/grpc-js protobufjs

Defining Proto Files

gRPC communication requires Protocol Buffers (proto files) to define message types and services. Let’s create a file called app.proto that defines a simple Hello service:

protoCopyEditsyntax = "proto3";

service HelloService {
  rpc sayHello (HelloRequest) returns (HelloResponse);
}

message HelloRequest {
  string name = 1;
}

message HelloResponse {
  string message = 1;
}

This proto file defines a service called HelloService with a method sayHello that accepts a HelloRequest and returns a HelloResponse.

Implementing the gRPC Service

grpc.service.ts

tsCopyEditimport { Injectable } from '@nestjs/common';
import { GrpcMethod } from '@nestjs/microservices';
import { HelloRequest, HelloResponse } from './interfaces/hello.interface';

@Injectable()
export class GrpcService {
  @GrpcMethod('HelloService', 'sayHello')
  sayHello(data: HelloRequest): HelloResponse {
    return { message: `Hello, ${data.name}!` };
  }
}

grpc.module.ts

tsCopyEditimport { Module } from '@nestjs/common';
import { GrpcService } from './grpc.service';

@Module({
  providers: [GrpcService],
})
export class GrpcModule {}

main.ts (gRPC Microservice Setup)

tsCopyEditimport { NestFactory } from '@nestjs/core';
import { GrpcModule } from './grpc.module';
import { Transport } from '@nestjs/microservices';

async function bootstrap() {
  const app = await NestFactory.createMicroservice(GrpcModule, {
    transport: Transport.GRPC,
    options: {
      package: 'hello', // gRPC package name
      protoPath: join(__dirname, './proto/app.proto'), // Path to the proto file
    },
  });
  await app.listen();
}

bootstrap();

In this setup:

  • @GrpcMethod is used to define a method for handling gRPC requests.
  • The sayHello method processes the request and returns a response with a greeting.

Best Practices for Building Microservices in NestJS

  1. Decouple Services: Microservices should be loosely coupled and have well-defined boundaries. Each service should manage its own data and logic.
  2. Use Event-Driven Architecture: For better scalability, use message brokers (like Redis) to decouple microservices further and handle asynchronous communication.
  3. Use Protocol Buffers with gRPC: When building efficient APIs, prefer gRPC and Protocol Buffers over JSON-based communication for better performance.
  4. Handle Failures Gracefully: Ensure that microservices can handle partial failures without affecting the entire system. Use retries and circuit breakers as needed.
  5. Keep Services Lightweight: Each service should only perform one responsibility and be lightweight, so it can be easily scaled and deployed independently.

Conclusion

In this module, we’ve learned how to build microservices in NestJS using three different transport layers: TCP, Redis, and gRPC. NestJS simplifies the creation of microservices with its flexible microservices module and support for various communication protocols.

By using TCP, Redis, and gRPC, you can create scalable, efficient, and maintainable systems that follow the principles of microservices architecture. Each of these communication methods is suitable for different use cases, and you can choose the one that best fits your application’s needs.