使用Express-GraphQL和React-Apollo的GraphQL订阅

问题描述:

我已经遵循Apollo的文档来设置客户端和服务器上的GraphQL订阅,虽然我90%在那里,但我无法弄清楚如何设置订阅渠道以及如何将突变连接到这些渠道,以便每当发生突变时,服务器就会将新数据推送到客户端。 (关于内容,我正在制作一个Reddit克隆,人们发布主题和其他人发表评论,所以当你看到“主题”或“主题列表”时,将这些视为帖子。)使用Express-GraphQL和React-Apollo的GraphQL订阅

到目前为止,我已经设置了阿波罗客户端订阅成功:

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,我看到:在文档侧菜单 My GraphiQIL UI showing the subscriptionSchema successfully

可用此订阅在我的阵营组成部分,我成功地利用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中。

我意识到这真的很漫长,但我一直在嘲笑我的头发,想弄清楚下一步是什么。任何帮助将非常感激!!感谢您的阅读!

是的,你缺少设置功能。你可以看看这个链接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); 
 
    } 
 
    ... 
 
}); 
 

 

 
....

+0

谢谢Locco0_0!但是我之前也尝试添加一个新的评论,我得到这个错误在控制台: 遗漏的类型错误:在WebSocket.client.onmessage 以及无法读取的不确定 财产“处理程序”: 参数无效返回从onSubscribe!返回值必须是一个对象!“ 有关更多的参考资料,现在我的addTopic突变(在codepen中,因为我无法在这里使用char限制):[link](https:// codepen。 io/bfitty/pen/jBoXda) 我仍然可以添加一个主题,但我必须按照惯例做,并刷新页面,让它显示在列表上。任何想法? –

+0

订阅定义看起来不错, TopicType'定义了吗? 在你的情况下,你可以删除args参数,因为你没有你想传递给你的订阅的参数。编号 } } ;' 第一个错误对我来说并不是很清楚,但是您可以在'componentWillReceiveProps(newProps)'函数中添加订阅,并检查订阅查询是否已加载 –

+0

而我刚刚在代码链接中看到您的设置一个新的pubsub()'。在这里你必须使用你添加到subscriptionManager的相同内容 –