DEV Community

adewale-codes
adewale-codes

Posted on

gRPC with NestJS: A Comprehensive Beginner's Guide

The world of software development is changing quickly, and creating scalable and effective microservices is crucial. It is frequently difficult to communicate across different services, particularly when low latency and great performance are desired. Introducing gRPC, a potent, open-source RPC framework developed by Google. When paired with NestJS, an advanced Node.js framework, gRPC offers a reliable inter-service communication solution. You will learn the basics of gRPC, how to integrate it with NestJS, and develop a basic chat service as an example by following this guide.

Understanding the Fundamentals

What is gRPC?
Google created the open-source gRPC (Google Remote Procedure Call) RPC (Remote Procedure Call) framework. It uses Protocol Buffers (protobuf) for serialization and HTTP/2 for transport to facilitate effective, language-neutral communication between distributed systems.

Key Features of gRPC:

  • Language Independence: Supports multiple programming languages.

  • HTTP/2 Support: Provides features like multiplexing and header compression.

  • Bidirectional Streaming: Supports streaming of data between client and server.

  • Automatic Code Generation: Reduces boilerplate code through protobuf definitions.

What is NestJS?

NestJS is a Node.js framework for creating scalable, dependable, and effective server-side applications. It makes use of both TypeScript and contemporary JavaScript features to offer a powerful development environment.

Key Features of NestJS:

  • Modular Architecture: Encourages a modular approach to application design.

  • Dependency Injection: Simplifies management of dependencies.

  • Extensive CLI: Provides tools to generate boilerplate code and manage the project.

  • Support for Multiple Transport Layers: Includes HTTP, WebSocket, and gRPC.

Setting Up the Project

Step 1: Creating a New NestJS Project
First, let's use the Nest CLI to establish a new NestJS project:

nest new grpc-chat-service
Enter fullscreen mode Exit fullscreen mode

Navigate into the project directory:

cd grpc-chat-service
Enter fullscreen mode Exit fullscreen mode

Step 2: Installing Necessary Dependencies
To integrate gRPC with NestJS, install the necessary dependencies:

npm install @nestjs/microservices grpc @grpc/proto-loader
Enter fullscreen mode Exit fullscreen mode

Defining the Protocol Buffers File

Protocol Buffers (protobuf) is an extendable, platform- and language-neutral method for serializing structured data. To specify our service contract, create a file called chat.proto in the src directory:

syntax = "proto3";

service ChatService {
  rpc SendMessage (Message) returns (Empty);
}

message Message {
  string content = 1;
}

message Empty {}

Enter fullscreen mode Exit fullscreen mode

In this definition:

  • Service: ChatService contains an RPC method SendMessage.

  • Messages: Defines the structure of Message and Empty.

Implementing the Server

Let's now put the server-side logic for our chat service into practice.
Step 1: Create a Controller

Create a new file named chat.controller.ts in the src directory:
import { Controller } from '@nestjs/common';
import { GrpcMethod } from '@nestjs/microservices';
import { Empty, Message } from './chat.grpc.pb';

@Controller()
export class ChatController {
  private messages: string[] = [];

  @GrpcMethod('ChatService', 'SendMessage')
  async sendMessage(data: Message): Promise<Empty> {
    console.log('Received message:', data.content);
    this.messages.push(data.content);
    console.log('Current messages:', this.messages);
    return {};
  }
}
Enter fullscreen mode Exit fullscreen mode
  • @GrpcMethod: Decorator to map the gRPC method to the NestJS method.
  • sendMessage Method: Logs the received message, stores it in an in-memory array, and prints the current list of messages. Step 2: Update the Module Update app.module.ts to include the ChatController:
import { Module } from '@nestjs/common';
import { ChatController } from './chat.controller';

@Module({
  controllers: [ChatController],
})
export class AppModule {}
Enter fullscreen mode Exit fullscreen mode

Implementing the Client

We'll now build a client in order to communicate with our gRPC server.
Step 1: Create a Client Class
Create a new file named chat.client.ts in the src directory:

import { Injectable } from '@nestjs/common';
import { ClientGrpc, ClientProxyFactory, Transport } from '@nestjs/microservices';
import { Message } from './chat.grpc.pb';
import { join } from 'path';

@Injectable()
export class ChatClient {
  private readonly client: ClientGrpc;

  constructor() {
    this.client = ClientProxyFactory.create({
      transport: Transport.GRPC,
      options: {
        url: 'localhost:5000',
        package: 'chat',
        protoPath: join(__dirname, 'chat.proto'),
      },
    });
  }

  async sendMessage(content: string): Promise<void> {
    const message: Message = { content };
    await this.client.getService('ChatService').sendMessage(message).toPromise();
  }
}
Enter fullscreen mode Exit fullscreen mode

In this client:

  • ClientProxyFactory.create: Creates a gRPC client.

  • sendMessage Method: Sends a message to the server.

Step 2: Integrate Client in Module
Update app.module.ts to include the ChatClient:

import { Module } from '@nestjs/common';
import { ChatClient } from './chat.client';
import { ChatController } from './chat.controller';

@Module({
  controllers: [ChatController],
  providers: [ChatClient],
})
export class AppModule {}

Enter fullscreen mode Exit fullscreen mode

Bootstrapping the Application

Bootstrapping is the process of starting the application, initializing necessary services, and getting the server up and running.
Update the main.ts file:

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { Transport } from '@nestjs/microservices';
import { join } from 'path';

async function bootstrap() {
  const app = await NestFactory.createMicroservice(AppModule, {
    transport: Transport.GRPC,
    options: {
      url: 'localhost:5000',
      package: 'chat',
      protoPath: join(__dirname, 'chat.proto'),
    },
  });
  await app.listenAsync();
}
bootstrap();
Enter fullscreen mode Exit fullscreen mode

In this code:

  • NestFactory.createMicroservice: Creates a microservice instance.

  • Transport Options: Specifies gRPC as the transport and provides necessary configuration like URL, package, and path to the protobuf file

  • app.listenAsync: Starts the microservice and listens for incoming gRPC requests.

Running and Testing the Application

Step 1: Start the Server
Run the server:

npm run start:dev
Enter fullscreen mode Exit fullscreen mode

Step 2: Use the Client to Send a Message
We can now use the ChatClient to send a message to our server. You can create a simple script to test this:
Create test-client.ts:

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ChatClient } from './chat.client';

async function testClient() {
  const app = await NestFactory.createApplicationContext(AppModule);
  const client = app.get(ChatClient);
  await client.sendMessage('Hello, gRPC!');
  await app.close();
}

testClient();
Enter fullscreen mode Exit fullscreen mode

Run the script:

`ts-node src/test-client.ts`
Enter fullscreen mode Exit fullscreen mode

You should see the server logging the received message and maintaining a list of messages.

Conclusion

We have examined how to integrate gRPC with NestJS to create effective microservices in this extensive article. We've gone over the basics of gRPC, used Protocol Buffers to build a service, used an in-memory message storage to provide server-side functionality, built a message-sending client, and bootstrapped our NestJS application. You now have the basis to use gRPC's power in your NestJS apps, allowing for high-performance and scalable inter-service communication. Just follow these instructions. Using gRPC and NestJS together provides a reliable and effective solution whether you're developing microservices, real-time apps, or intricate distributed systems.

Top comments (0)