typescriptmicroservicesmqttnestjsservice-broker

Nestjs ClientMqtt.emit publish both pattern and data to broker rather than only data


I use Nestjs to publish data to a Mqtt Broker, but it sends the both pattern and data rather than only data like this:

{
    "pattern": "test/test",
    "data": "Data"
}

In the app.module.ts, I import MQTT Client like this:

@Module({
    imports: [
        ClientsModule.register([
            {
                name: 'MQTT_CLIENT',
                transport: Transport.MQTT,
                options: {
                    url: 'tcp://abc.abc.com',
                    username: 'name',
                    password: 'psswrd',
                    port: 1883,
                },
            },
        ]),
    ],
    controllers: [AppController],
    providers: [AppService],
})

and in app.controller.ts:

@Controller()
export class AppController {
    constructor(@Inject('MQTT_CLIENT') private client: ClientMqtt) {}

    async onApplicationBootstrap() {
        await this.client.connect();
    }

    @Get()
    getHello(): string {
        this.client.emit('test/test', 'Data')
        return 'Done';
    }
}

I also found that in the ClientMqtt proxy source code, method publish is to publish all the partialPacket which is the JSON {pattern, data} rather than only packet.data

protected publish(
    partialPacket: ReadPacket,
    callback: (packet: WritePacket) => any,
  ): Function {
    try {
      const packet = this.assignPacketId(partialPacket);
      const pattern = this.normalizePattern(partialPacket.pattern);

      ...
        this.mqttClient.publish(
          this.getAckPatternName(pattern),
          JSON.stringify(packet),
        );
      });
      ...
  }

So if I just want to use ClientMqtt proxy but just only publish the data field of the packet, how can I do so?


Solution

  • You can change the structure of the message sent to the MQTT broker using the serializers. For doing this you need include the 'serializer' attribute in the ClientsModule registration:

    @Module({
        imports: [
            ClientsModule.register([
                {
                    name: 'MQTT_CLIENT',
                    transport: Transport.MQTT,
                    options: {
                        url: 'tcp://abc.abc.com',
                        username: 'name',
                        password: 'psswrd',
                        port: 1883,
                        serializer: new OutboundResponseSerializer()
                    },
                },
            ]),
        ],
        controllers: [AppController],
        providers: [AppService],
    })
    

    With this change you need to create the 'OutboundResponseSerializer' class in other file that implements the method 'serialize':

    import { Serializer, OutgoingResponse } from '@nestjs/microservices';
    import { Logger } from '@nestjs/common';
    
    export class OutboundResponseSerializer implements Serializer {
    
        private readonly logger = new Logger('OutboundResponseIdentitySerializer');
    
        serialize(value: any): OutgoingResponse {
          this.logger.debug(`-->> Serializing outbound response: \n${JSON.stringify(value)}`);
          return value.data;
        }
    }
    

    With this changes, your messages only contains the data information.

    You can find more information about this in the section 'Implementing Serializers and Deserializers' in this link: https://dev.to/nestjs/integrate-nestjs-with-external-services-using-microservice-transporters-part-3-4m20