NestJs for microservices of all types TCP/MQs

NestJs for microservices?

When creating a microservice, there are several major programming languages ​​to choose from with robust frameworks. NestJs has many tools for us to create a robust, organized, and testable application. A highlight is a power of dependency injection that the framework brings, where we can inject a module into another one, facilitating code reuse. But it’s worth noting that when this dependency injection makes modules dependent on each other, we hurt some Clean Architecture concepts.

The project that we will create next came from an idea of ​​experimenting with the development of an API that is able to keep its input interface, responses, and business rules highly independent of databases and frameworks.

Creation of our microservice

We’ll start creating our microservice thinking about a problem that it can solve so it’s easier to define the functionality that we’ll work on. The communication protocol that we will implement is TCP, which will be responsible for operations and we will use PacketSender for testing purposes, an open-source application that allows us to send network packets that support TCP.

Implementing a microservice via HTTP would be no different than implementing an API using Node.JS just because a microservice has a well-defined architecture and scope, so we will choose to use an asynchronous pattern with TCP packets which we will communicate with our microservice, and hence the choice of Nest.JS as it has many built-in features making it easier for us to create a microservices architecture.

We’re going to divide the development into four stages so this tutorial doesn’t get too extensive, they are:

  • Microservice structure and configuration
  • Creating a message pattern to communicate with the microservice
  • Performing microservice tests using PacketSender
  • We leave this step as the icing on the cake in the end I’ll tell you what’s next in the next chapter 😄

Microservice structure and configuration

In this step we will create a new application in NestJS using your CLI using the command below:

npx @nestjs/cli new products-microservice

Note: if you do not have npx installed, go to the link https://www.npmjs.com/package/npx

Now that your app has been created, make sure you are at the root of the project and install a library @nestjs/microservices.

cd products-microservice && yarn add @nestjs/microservices

We need to modify the main.ts leaving as the code snippet below:

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

// Create the microservice options object
const microserviceOptions = {
  transport: Transport.TCP,
  options: {
    host: process.env.HOST, //
    port: process.env.PORT,
  },
};

(async () => {
  const app: INestMicroservice = await NestFactory.createMicroservice(
    AppModule,
    microserviceOptions,
  );
  
  await app.listen();

  console.info('Microservice is listening...', process.env.PORT || 8080);

})();

NestJS supports several built-in transport layer implementations. The code above will create a microservice that communicates through the TCP transport layer to port 8080.

We have the option of using a message pattern or an event pattern to communicate with the microservice.

The message pattern acts as a request-response method, it is recommended for exchanging messages between services and the event pattern for when you just want to post events without waiting for a response.

We will just implement the functionality that will create a product based on the given input and we will get the created product. So let’s register a named message pattern create_product in the file app.controller.ts.

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @MessagePattern('create_product')
  async createProduct(@Payload() payload: CreateProductDto) {
    const product = await this.appService.createProduct(payload);
    return product;
  }
}

Next, we will abstract the logic of creating a new product, it can be implemented in different ways based on the needs and the database used, and we will focus only on requirements related to microservices.

import { IsString, IsEmail, IsNotEmpty } from 'class-validator';

export class CreateProductDto {
  @IsNotEmpty()
  @IsEmail()
  name: string;
 
  @IsNotEmpty()
  @IsNumber()
  price: number;
}

The payload we use to create a new product will look like this:

And finally, the most important thing is our service, which will be responsible for saving this data in the bank.

...
import Product from '../entity/product.entity';
import { CreateProductDto } from '../dto/create-product.dto';
...

@Injectable()
export default class AppService {

  constructor(
    @InjectRepository(Product) private readonly productRepository: Repository<Product>,
  ){}
  
  async createProduct(body: Partial<Product>): Promise<UserDto> {
    try {
     	const product = new Product();
	product.name = body.name;
	product.price = body.price;
      
      	const productCreated = await this.productRepository.save(product);
      
      	return productCreated;

    } catch (e) {
	throw new InternalServerErrorException('Error');
    }
  }
...
}

With all our code created we can perform the test in our application using PackatSender.

Performing microservice tests using PacketSender

Now that we have our microservice configured and structured we need to perform the test to check if everything is working, for that we will use PacketSender to send a TCP packet to our application. Set the Address and Port to 127.0.0.1:8080 and select TCP from the drop-down menu on the right. To encode our message, use the ASCII field and fill it in with the following value:

122#{"pattern":"create_product",
"data":{"name":"G Suite","price":120},
"id":"ce51ebd3-32b1-4ae6-b7ef-e018126c4cc4"}
  • pattern- is the message we define in our microservicecreate_product,;
  • data- is the JSON object we want to send, an object with a nameand price;

The value 122 represents the length of our message starting from the first key to the last (both included).

References

Conclusion

The NestJS provides the possibility to build lightweight, well-structured and amazing microservices. Out-of-the-box tools and features make development, extension, and maintenance nice and efficient.

Comments