Scenario
I have a sensor node which publishes information on a specific MQTT Topic (sent to a Mosquitto broker). The data sent is a pure string.
Backend
currently I am using apollo-server-express
to build a GraphQL Server. I wish to use `graphql-mqtt-subscriptions to:
- Subscribe to the MQTT Broker
- Read the information on a specific topic and just return it to the
graphiql
UI
dependencies
"dependencies": {
"apollo-server-express": "^2.8.1",
"express": "^4.17.1",
"graphql": "^14.4.2",
"graphql-mqtt-subscriptions": "^1.1.0",
"graphql-subscriptions": "^1.1.0",
"graphql-tools": "^4.0.5",
"mqtt": "^3.0.0",
"subscriptions-transport-ws": "^0.9.16"
},
Code Snippets
the entrypoint server.js
code:
import express from 'express';
import {ApolloServer } from 'apollo-server-express';
import { typeDefs } from './graphql/schema';
import { resolvers } from './graphql/resolvers';
import { createServer } from 'http';
const server = new ApolloServer({ typeDefs, resolvers});
const app = express();
server.applyMiddleware({ app });
const httpServer = createServer(app);
server.installSubscriptionHandlers(httpServer);
httpServer.listen({port: 4000}, () => {
console.log(` Server ready at http://localhost:4000/${server.graphqlPath}`)
console.log(` Subscriptions ready at ws://localhost:4000/${server.subscriptionsPath}`)
});
the typeDefs
Schema for GraphQL is the following:
type Result {
data: String
}
type Subscription {
siteAdded(topic: String): Result
}
schema {
query: Query
mutation: Mutation
subscription: Subscription
}
where siteAdded(topic: String)
will take the topic the MQTT needes to subscribe to. Example:
subscription {
siteAdded(topic: "test/1/env") {
data
}
The resolvers.js
looks like the following (as mentioned in may documentations):
import { MQTTPubSub } from 'graphql-mqtt-subscriptions';
import { connect } from 'mqtt';
const client = connect('mqtt://my.mqtt.broker.ip.address', {
reconnectPeriod: 1000,
});
const pubsub = new MQTTPubSub({
client
});
export const resolvers: {
Subscription: {
siteAdded: {
subscribe: (_, args) => {
console.log(args.topic); // to check if this gets called or not.
pubsub.asyncIterator([args.topic]);
}
}
}
};
Inference
the console.log
on the args.topic
gets called but after that the following error in graphiql
:
{
"error": {
"message": "Subscription field must return Async Iterable. Received: undefined"
}
}
If I perform a return pubsub.asyncIterator()
:
It provides the timely data from the Broker but the output is null
:
{
"data": {
"siteAdded": null
}
}
I have added the Websockets middleware in the server.js
mentioned above according to the Apollo Docs
Where Am I going wrong here and how to just add the data coming from the subscribed topic to graphiql
?