使用Express-GraphQL和React-Apollo进行GraphQL订阅

时间:2017-04-06 15:27:32

标签: reactjs express publish-subscribe graphql apollo

我跟随Apollo的文档在客户端和服务器上设置了GraphQL订阅,虽然我90%在那里,但我无法弄清楚如何设置订阅频道以及如何将突变连接到这些频道这样,每当发生突变时,服务器都会将新数据推送到客户端。 (对于内容,我正在制作Reddit克隆,人们发布主题,其他人对其进行评论。因此,当您看到“主题”或“主题列表”时,请将其视为帖子。)

到目前为止,我已成功为订阅设置了Apollo Client:

const wsClient = new SubscriptionClient('ws://localhost:3001/subscriptions', {
  reconnect: true
});

const networkInterface = createNetworkInterface({
    uri: '/graphql',
    opts: {
        credentials: 'same-origin'
    }
});

const networkInterfaceWithSubscriptions = addGraphQLSubscriptions(
  networkInterface,
  wsClient,
);

const client = new ApolloClient({
    networkInterface: networkInterfaceWithSubscriptions,
    dataIdFromObject: o => o.id
});

我也为订阅设置了后端。这是我的server.js文件:

//===========================================================
//Subscription Managaer
//===========================================================
const pubsub = new PubSub();
const subscriptionManager = new SubscriptionManager({
  schema: schema,
  pubsub: pubsub
});

//=====================================
//WebSocket + Express Server
//=====================================

const server = createServer(app);

//setup listening port
server.listen(3001, ()=>{
    new SubscriptionServer(
    {
        subscriptionManager: subscriptionManager,
        onConnect: (connectionParams, webSocket) => {
            console.log('Websocket connection established');
        },
        onSubscribe: (message, params, webSocket) => {
            console.log("The client has been subscribed", message, params);
        },
        onUnsubsribe: (webSocket) => {
            console.log("Now unsubscribed");
        },
        onDisconnect: (webSocket) => {
            console.log('Now disconnected');
        }
    }, 
    {
        server: server,
        path: '/subscriptions',
    });
    console.log('Server is hot my man!');
})

我知道这些都是成功的,因为我在终端中记录了“已建立Websocket连接”消息。

接下来是实际订阅 - 我创建了一个订阅模式类型(就像查询和突变一样):

const SubscriptionType = new GraphQLObjectType({
    name: 'Subscription',
    fields: () => ({
        topicAdded: {
            type: TopicType,
            args: {repoFullName: {type: GraphQLString}}, //I don't understand what repoFullName is - I was trying to follow the Apollo docs, but they never specified that
            resolve(parentValue, args){
                return parentValue;
            }

        }
    })
});

module.exports = SubscriptionType;

并将其合并到我的根模式中。所以当我查看GraphiQL时,我看到:这个订阅在Docs侧面菜单中可用 My GraphiQIL UI showing the subscriptionSchema successfully

在我的React组件中,我使用Apollo的subscribeToMore方法成功“订阅”它:

const TOPICS_SUBSCRIPTION = gql`
    subscription OnTopicAdded($repoFullName: String){
        topicAdded(repoFullName: $repoFullName){
            id
        }
    }
`;

class TopicList extends Component {
    componentDidMount() {
        this.createMessageSubscription = this.props.data.subscribeToMore({
          document: TOPICS_SUBSCRIPTION,
          // updateQuery: (previousState, {subscriptionData}) => {
          //   const newTopic = subscriptionData.data.Topic.node
          //   const topics = previousState.findTopics.concat([newTopic])
          //   return {
          //     findTopics: topics
          //   }
          // },
          onError: (err) => console.error(err)
        })

      } //...

我得到了“客户端已订阅”消息,我的终端已登录。但这就是我被困住的地方。我已经阅读了SubscriptionManager的SetupFunction,但这并没有包含在Apollo的文档中。我找不到如何将'createTopic'变种映射到此订阅,以便每当有人添加新主题时,它会弹出TopicList。

我意识到这真的很长,但我一直在拉扯我的头发以确定下一步是什么。任何帮助将非常感激!!谢谢你的阅读!

1 个答案:

答案 0 :(得分:1)

是的,你缺少设置功能。您可以查看此链接GraphQL subscription docu或此example

它应该如何运作: 首先,您需要发布已更改数据的通道。在你的情况下,它可能看起来像这样:



const manager = new sub.SubscriptionManager({
  schema,
  pubSub,

  setupFunctions: {
    topicAdded: (options, args) => ({ // name of your graphQL subscription
      topicAddedChannel: { // name of your pubsub publish-tag
        filter: (topic) => {
          console.log(topic); //should always show you the new topic if there is a subscribed client
          return true; // You might want to add a filter. Maybe for guest users or so
        },
      },
    }),
  },
});




在这里,您会看到订阅中需要args: {repoFullName: {type: GraphQLString}}参数。如果要根据" repoName"过滤订阅。这意味着只有订阅者使用" repoName"因为参数得到更新。

接下来,您需要一个调用pubsub.publish函数的位置。在你的情况下,添加主题变异已经过去。可能看起来像这样:



...

const topic = new Topic(/* args */);
topic.save((error, topic) => {
  if (!error) {
    pubsub.publish("topicAddedChannel", topic);
  }
  ...
});


....