0

设想

我有一个传感器节点,它发布有关特定 MQTT 主题的信息(发送到 Mosquitto 代理)。发送的数据是纯字符串。

后端

目前我正在使用apollo-server-express构建 GraphQL 服务器。我希望使用`graphql-mqtt-subscriptions来:

  • 订阅 MQTT 代理
  • 阅读特定主题的信息并将其返回到graphiqlUI

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}`)
});

typeDefsGraphQL的架构如下:


type Result {
        data: String
}

type Subscription {
        siteAdded(topic: String): Result
    }

schema {
  query: Query
  mutation: Mutation
  subscription: Subscription
}

wheresiteAdded(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()

它提供来自 Broker 的及时数据,但输出为null

{
  "data": {
    "siteAdded": null
  }
}

我根据Apollo Docsserver.js在上面添加了 Websockets 中间件

我在哪里出错以及如何将来自订阅主题的数据添加到graphiql

4

1 回答 1

0

概括

更新

注意事项

  • NPM Registry v1.1.0中的+和等通配符不可用。但是,存储库已经有了实现。存储库的所有者需要更新注册表。请参阅未解决的问题#graphql-mqtt-subscriptionsgraphql-mqtt-subscriptions

  • 我目前正在使用 MQTT 订阅的完整主题,以便从传感器获取数据,test/1/env例如test/+/env

发展更新

  • 以前我以原始字符串格式(纯文本)从传感器发送数据,因此我更新了固件以使用 JSON 字符串发送数据,如下所示:

      {"data": "temp=23,humid=56 1500394302"}
    

解决方案

  1. 正如@Dom 和@DanielRearden 的评论中提到的,return如果我使用了花括号,我最初会忘记添加{}。例如:

        Subscription: {
        siteAdded: {
            subscribe: (_, args) => {
                console.log(args.topic); // to check if this gets called or not.
                return pubsub.asyncIterator([args.topic]);
    
            }
        }
    }
    

    或者我只是删除了括号并return编写了解析器,如下所示:

        Subscription: {
           siteAdded: {
               subscribe: (_, args) => pubsub.asyncIterator([args.topic]),
           }
        }
    

    null如查询中所述,这仍在返回我。

  2. 通过遵循 Apollo 的有效负载转换文档,我能够从订阅中获取数据,在我的解析器中,我执行了以下操作:

       Subscription: {
        siteAdded: {
            resolve: (payload) => {
                return {
                    data: payload.data,
                };
            },
            subscribe: (_, args) => pubsub.asyncIterator([args.topic]),
        }
    }
    

    必须为 Schema 相应地解析有效负载。

结果

现在订阅如下工作就像一个魅力:

    subscription {
        siteAdded(topic: "test/1/env") {
            data
        }
    }

提供以下结果:

{
  "data": {
    "siteAdded": {
      "data": "temp=27.13,humid=43.33 1565345004"
    }
  }
}
于 2019-08-09T11:20:28.177 回答