Format request before send by ClientProxy

I use microservices and RabbitMQ as a transporter. My microservices communicate with each other, so one of them can send message to another one. I use the following way to send messages:

await this.client.send(SOME_COMMAND, obj).toPromise();

Now I need to format objects I send in all requests to any microservice in one place. For example add reqId, or serialize Map. Is it possible?


Solution 1:

1. Per controller solution. here for simplicity I removed the handler part:

@Controller()
export class AppController {
  constructor(@Inject('MATH_SERVICE') private client: ClientProxy) {
     let send = client.send.bind(client);
     client.send = function (pattern, payload) {
      
       return send(pattern, { payload, systemWideProp: ""})
    }
  }
  sum() {
    this.client.send(COMMAND, obj)
  }
}

2. This could be as a provider for injecting it on each controller you want using your rabbitmq client service:

custom-client-proxy.ts

import { Inject, Injectable } from '@nestjs/common';
import { ClientProxy } from '@nestjs/microservices';

@Injectable()
export class CustomClientProxy {
    constructor(@Inject('MATH_SERVICE') private client: ClientProxy) { }
    send(pattern, payload) {
        // payload and pattern manipulations such as: 
        // payload.say = "Hi";
        // const scopePattern = { cmd: `${pattern.cmd}_dev` };
        return this.client.send(pattern, payload)
    }
}

app.module.ts

import { Module } from '@nestjs/common';
import { ClientsModule, Transport } from '@nestjs/microservices';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { CustomClientProxy } from './custom-client-proxy';

@Module({
  imports: [ClientsModule.register([{
    name: 'MATH_SERVICE',
    transport: Transport.RMQ,
    options: {
      urls: ['amqp://localhost:5672'],
      queue: 'math_queue'
    },
  }])],
  controllers: [AppController],
  providers: [AppService, CustomClientProxy],
  exports: [CustomClientProxy] // export here for other modules of your app
})
export class AppModule { }

app.controller.ts also any controller you have imported under app's modules

@Controller()
export class AppController {
  constructor(private client: CustomClientProxy) {}
  sum() {
    this.client.send(COMMAND, obj)
  }

}

3. When you need to use this functionality for more than one queue:


// custom-client-proxy.ts

@Injectable()
export class CustomClientProxy {
    constructor() { }
    send(client: ClientProxy, pattern, payload) {
        // payload and pattern manipulations such as: 
        // payload.say = "Hi";
        // const scopePattern = { cmd: `${pattern.cmd}_dev` };
        return client.send(pattern, payload)
    }
}

// app.module.ts
@Module({
  imports: [ClientsModule.register([{
    name: 'MATH_SERVICE',
    transport: Transport.RMQ,
    options: {
      urls: ['amqp://localhost:5672'],
      queue: 'math_queue'
    },
  },
  {
    name: 'MESSAGE_SERVICE',
    transport: Transport.RMQ,
    options: {
      urls: ['amqp://localhost:5672'],
      queue: 'message_queue',
    },
  }])],
  controllers: [AppController],
  providers: [AppService, CustomClientProxy],
  exports: [CustomClientProxy]
})
export class AppModule { }

// app.controller.ts
@Controller()
export class AppController {

  constructor(
    @Inject('MATH_SERVICE') private mathClient: ClientProxy,
    @Inject('MESSAGE_SERVICE') private messageClient: ClientProxy,
    private client: CustomClientProxy) {}

  
  sum(a) {
    return this.client.sendTo(this.mathClient, pattern, payload);
  }
}