Сценарий
У меня есть сенсорный узел, который публикует информацию по определенной теме MQTT (отправляется брокеру Mosquitto). Отправляемые данные представляют собой чистую строку.
Бэкенд
в настоящее время я использую apollo-server-express
для создания сервера GraphQL. Я хочу использовать `graphql-mqtt-subscriptions, чтобы:
- Подпишитесь на брокера MQTT
- Прочитайте информацию по определенной теме и просто верните ее в
graphiql
интерфейс.
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"
},
Фрагменты кода
код точки входа server.js
:
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}`)
});
схема typeDefs
для GraphQL следующая:
type Result {
data: String
}
type Subscription {
siteAdded(topic: String): Result
}
schema {
query: Query
mutation: Mutation
subscription: Subscription
}
где siteAdded(topic: String)
возьмет тему, на которую MQTT должен подписаться. Пример:
subscription {
siteAdded(topic: "test/1/env") {
data
}
resolvers.js
выглядит следующим образом (как указано в майской документации):
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]);
}
}
}
};
Вывод
вызывается console.log
на args.topic
, но после этого следующая ошибка в graphiql
:
{
"error": {
"message": "Subscription field must return Async Iterable. Received: undefined"
}
}
Если я выполняю return pubsub.asyncIterator()
:
Он предоставляет своевременные данные от брокера, но вывод null
:
{
"data": {
"siteAdded": null
}
}
Я добавил промежуточное ПО Websockets в server.js
, упомянутое выше, в соответствии с Документами Apollo< /а>
Где я ошибаюсь и как просто добавить данные, поступающие из подписанной темы, в graphiql
?
return
в преобразователе подписки.return pubsub.asyncIterator([args.topic]);
- person Dom   schedule 08.08.2019return
результат вызоваpubsub.asyncIterator()
, как сказал @Dom. Как вы тестируете подписку? После того, как вы подпишетесь на Playground, вам нужно будет каким-то образом инициировать вызовpublish
(например, открыв Playground на другой вкладке и отправив мутацию, вызывающуюpublish
). - person Daniel Rearden   schedule 08.08.2019publish
. У меня уже есть датчик, который публикуется в темеtest/1/env
, и поскольку я использую подстановочный знакtest/+/env
, данные должны быть доступны. - person Shan-Desai   schedule 08.08.2019publish
, и по крайней мере посмотрел бы, работает ли она так, как ожидалось. Предполагая, что это так, вы можете отлаживать оттуда. Может несоответствие в названиях тем? - person Daniel Rearden   schedule 08.08.2019