mqttjs / MQTT.js

The MQTT client for Node.js and the browser
Other
8.59k stars 1.42k forks source link

documentation: example to use request-response paradigm (MQTT V5) #1034

Closed botsbuzz closed 4 years ago

botsbuzz commented 4 years ago

Anyone could help with this?

Andreyooo commented 4 years ago

Use the parameters responseTopic and optionally correlationData in the publish function, I haven't used this feature yet but I guess the subscriber has to check if a responseTopic was set.

Here is a great article with more information: https://www.hivemq.com/blog/mqtt5-essentials-part9-request-response-pattern/

botsbuzz commented 4 years ago

Thank you so much for your help!

dsbaars commented 4 years ago

Although the issue is closed, I would like to give an example for anyone who needs this since this cost me quite some time to figure this out.

Make sure your broker supports MQTT v5. Initialize both publisher and subscriber with these client options:

        this.mqttClient = mqtt.connect(this.mqttEndpoint, {
            protocolVersion: 5,
            properties: {
                requestResponseInformation: true,
                requestProblemInformation: true,
            }
        });

Think of a way to correlate request and response, I used the uuid package:

let corId = uuidv4();

// You can use this to get the response back to your invoking method
// This should be clear to you when reading until the end
        let res = new Promise((resolve, reject) => {
            this.ee.once(corId, resolve)
        });

If you publish a message, add properties responseTopic and correlationData to it, at the time of writing these are not yet in the type-definitions so when using TypeScript you need to use // @ts-ignore.

        this.getMqttClient().publish(topic, JSON.stringify(data), {
            // @ts-ignore
            properties: {
                responseTopic: 'your/response/topic',
                correlationData: corId 
            },
        });

Now, the subscriber should get those two properties in the packet parameter:

this.mqttClient.on('message', (topic, message, packet) => {
            if (topic.startsWith(this.topicPrefix)) {
                try {
                    // @ts-ignore
                    let responseTopic = packet.properties.responseTopic;
                    let correlationData = packet.properties.correlationData;
                }
                catch (e) {
                  ...
                }
            }
        });

Use these in your response as well:

            this.mqttClient.publish(responseTopic, JSON.stringify(message), {
                // @ts-ignore
                properties: {
                    correlationData: packet.properties.correlationData
                }
            });

This is probably not a very beautiful solution to solve the last piece of the puzzle, but I could not think of another way. To correlate the response at the requesters side, I used the node.js EventEmitter which broadcoasts an event with the correlationData

this.mqttClient.on('message', (topic, payload, packet) => {
            if (topic === 'your/response/topic') {
                this.ee.emit( packet.properties.correlationData.toString(), payload.toString() )
            }
        });

// You can use this to get the response back to your invoking method
        let res = new Promise((resolve, reject) => {
            this.ee.once(corId, resolve)
        });
PratikGupta114 commented 1 year ago

Thank you @dsbaars. This was quite a help.