Open In App

Custom Transporters in NestJS

Last Updated : 30 Jul, 2024
Comments
Improve
Suggest changes
Like Article
Like
Report

NestJS is a progressive Node.js framework for building efficient, reliable, and scalable server-side applications. One of its powerful features is the microservices architecture, which allows developers to build distributed systems.

NestJS provides built-in transporters like TCP, Redis, and NATS, but sometimes you might need to create a custom transporter to meet specific requirements. This article explores how to create and use custom transporters in NestJS.

What are Transporters in NestJS?

Transporters in NestJS are responsible for communication between microservices. They abstract the underlying communication protocol, allowing developers to focus on business logic. NestJS provides several built-in transporters, but custom transporters can be created to use different protocols or integrate with specific services.

The built-in transporters are:

  • TCP: Default transport layer, suitable for direct service-to-service communication.
  • Redis: Used for Pub/Sub messaging patterns.
  • NATS: Lightweight, high-performance messaging system.
  • MQTT: Protocol for IoT and M2M communication.
  • gRPC: Google’s RPC framework for microservices.

While these built-in transporters cover a wide range of use cases, there are situations where a custom transporter is necessary. For example, integrating with a legacy system or a third-party service with a unique protocol might require a custom solution.

When to Use a Custom Transporter

Creating a custom transporter might be necessary when:

  • You need to integrate with a third-party service that uses a proprietary protocol.
  • You want to optimize performance with a specialized communication protocol.
  • The built-in transporters do not meet specific application requirements.

Steps to Create Nest Application

Step 1: Install NestJS globally in your system

To create a new NestJS project, you can use the NestJS CLI (@nestjs/cli). Install it globally using npm:

npm install -g @nestjs/cli

Step 2: Initialize NestJS Project

Creating a New NestJS Project using the below command

nest new nest-gfg
cd nest-gfg

You will be prompted to choose a package manager. Select either npm or yarn according to your preference.

Step 3: Install Required Packages

Install the @nestjs/microservices package if it’s not already included:

npm install @nestjs/microservices
npm install @nestjs/platform-socket.io
npm install @nestjs/websockets

Step 4: Create the Custom Transporter

Create a new file custom.transporter.ts and app.gateway.ts in the src directory.

Folder Structure

wefr
Nestjs folder structure

Dependencies

"dependencies": {
"@nestjs/common": "^10.0.0",
"@nestjs/core": "^10.0.0",
"@nestjs/microservices": "^10.3.10",
"@nestjs/platform-express": "^10.0.0",
"@nestjs/platform-socket.io": "^10.3.10",
"@nestjs/websockets": "^10.3.10",
"reflect-metadata": "^0.2.0",
"rxjs": "^7.8.1"
}

Example: Creating Custom Transporter

JavaScript
//src/custom.transporter.ts

import {
    ClientProxy,
    ReadPacket,
    WritePacket,
    CustomTransportStrategy,
} from '@nestjs/microservices';
import { Logger } from '@nestjs/common';

export class CustomTransporter
    extends ClientProxy
    implements CustomTransportStrategy {
    private readonly logger = new Logger(CustomTransporter.name);

    constructor(private readonly options: any) {
        super();
    }

    async connect(): Promise<void> {
        this.logger.log('Custom Transporter connected...');
        // Implement your connection logic here
    }

    async close(): Promise<void> {
        this.logger.log('Custom Transporter closed...');
        // Implement your close logic here
    }

    listen(callback: () => void): void {
        this.logger.log('Custom Transporter is listening...');
        // Implement your custom transport logic here
        callback();
    }

    protected dispatchEvent(packet: ReadPacket<any>): Promise<any> {
        this.logger.log(`Dispatch event: ${JSON.stringify(packet)}`);
        // Implement your dispatch event logic here
        return Promise.resolve();
    }

    protected publish(
        packet: ReadPacket<any>,
        callback: (packet: WritePacket<any>) => void,
    ): () => void {
        this.logger.log(`Publish event: ${JSON.stringify(packet)}`);
        // Simulate an immediate response for testing purposes
        callback({ response: 'response' });
        return () => { };
    }
}
JavaScript
//main.ts

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { CustomTransporter } from './custom.transporter';
import { MicroserviceOptions } from '@nestjs/microservices';

async function bootstrap() {
    const app = await NestFactory.create(AppModule);

    app.connectMicroservice<MicroserviceOptions>({
        strategy: new CustomTransporter({
            /* Custom options */
        }),
    });

    await app.startAllMicroservices();
    await app.listen(3000);
}
bootstrap();
JavaScript
//app.module.ts

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { AppGateway } from './app.gateway';

@Module({
    imports: [],
    controllers: [AppController],
    providers: [AppService, AppGateway],
})
export class AppModule { }
JavaScript
//app.controller.ts

import { Controller, Get } from '@nestjs/common';
import {
    ClientProxy,
    ClientProxyFactory,
    CustomClientOptions,
} from '@nestjs/microservices';
import { CustomTransporter } from './custom.transporter';

@Controller()
export class AppController {
    private client: ClientProxy;

    constructor() {
        const customClientOptions: CustomClientOptions = {
            customClass: CustomTransporter,
            options: {
                /* Custom options */
            },
        };
        this.client = ClientProxyFactory.create(customClientOptions);
    }

    @Get()
    async sendMessage() {
        const pattern = { cmd: 'custom_message' };
        const data = { text: 'Hello from custom transporter' };
        const response = await this.client.send(pattern, data).toPromise();
        return response;
    }

    @Get('custom-message')
    async getCustomMessage() {
        const pattern = { cmd: 'custom_message' };
        const data = { text: 'Hello from custom transporter' };
        const response = await this.client.send(pattern, data).toPromise();
        return response;
    }
}
JavaScript
//app.gateway.ts

import {
    SubscribeMessage,
    WebSocketGateway,
    MessageBody,
} from '@nestjs/websockets';

@WebSocketGateway()
export class AppGateway {
    @SubscribeMessage('message')
    handleMessage(@MessageBody() message: string): string {
        return message;
    }
}
JavaScript
//app.service.ts

import { Injectable } from '@nestjs/common';

@Injectable()
export class AppService {
    getHello(): string {
        return 'Hello World!';
    }
}

To start the application run the following command.

npm run start

Output

resize
Custom Transporters in NestJS


Next Article

Similar Reads