Apollo GraphQL 订阅

Posted

技术标签:

【中文标题】Apollo GraphQL 订阅【英文标题】:Apollo GraphQL Subscriptions 【发布时间】:2017-09-19 03:23:24 【问题描述】:

我在 Apollo 中订阅 GraphQL 时遇到问题。我想订阅关于主题的添加“观点”(基本上在帖子上添加了 cmets),我很确定我的服务器设置正确。客户给我带来了麻烦。 (如果这个问题看起来很眼熟,我之前问过它并认为我得到了答案,但没有去)。这是我的订阅模式:

type Subscription 
  perspectiveAdded: Perspective


schema 
  query: RootQuery
  mutation: Mutation
  subscription: Subscription

我的订阅解析器:

Subscription: 
    perspectiveAdded(perspective) 
      return perspective;
    
  

我的订阅管理器:

const pubsub = new PubSub();
const subscriptionManager = new SubscriptionManager(
  schema,
  pubsub,
  setupFunctions: 
    perspectiveAdded: (options, args) => 
      perspectiveAdded: 
        filter: (topic) => 
          return topic
        
      
    ,
  
);

export  subscriptionManager, pubsub ;

我的 addPerspective 突变的最后一部分是(订阅的事件触发器):

//...    
return perspective.save((error, perspective) => 
   if(error)
     console.log(error);
   

   //Publish it to Subscription channel
   pubsub.publish('perspectiveAdded', perspective);
);

然后我连接了实际的服务器以支持订阅:

const PORT = process.env.PORT || 4000;
const server = createServer(app);

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

我也正确连接了客户端,因为在我的终端中我看到“Websocket 连接已建立”消息。我很难过的部分是如何实际调用订阅。根据 Apollo 博客,我应该能够在 GraphiQL 中测试订阅(因为我使用的是 apollo 服务器,现在是 graphql-server-express),但它显示“Resolve function for \"Subscription.perspectiveAdded\”返回未定义”。

对于我的组件,我尝试连接“subscribeToMore”,但在浏览器控制台中,我收到一个错误对象,上面写着“onSubscribe 返回的参数无效!返回值必须是一个对象!”我不确定它指的是哪个对象。

这是我的订阅查询,称为透视订阅:

export default gql`
subscription 
  perspectiveAdded 
    id
    content
  

`;

以及连线组件:

constructor(props)
      super(props);
      this.state = ;
      this.subscription = null;
    



    componentWillReceiveProps(nextProps) 
      if (!this.subscription && !nextProps.data.loading) 
        let  subscribeToMore  = this.props.data
        this.subscription = subscribeToMore(
          
            document: perspectiveSubscription,
            updateQuery: (previousResult,  subscriptionData ) => 
              if(!subscriptionData.data)
                console.log('no new subscription data');
                return previousResult;
              

              const newPerspective = subscriptionData.data.perspectiveAdded;
              console.log(newPerspective);
              return Object.assign(, previousResult, newPerspective);
            
          
        )
      

从这里,我在终端中收到一条消息,说客户端已订阅,但我仍然收到上面提到的错误对象。几天来我一直在为此烦恼-你们知道我在这里缺少什么吗?具体来说,客户端有什么想法吗?谢谢大家!

【问题讨论】:

【参考方案1】:

似乎服务器端不正确,因为添加了订阅,而 graphiql 也没有提供正确的结果。

我建议您检查频道定义:

const pubsub = new PubSub();
const subscriptionManager = new SubscriptionManager(
  schema,
  pubsub,
  setupFunctions: 
    perspectiveAdded: (options, args) => 
      perspectiveAdded: 
        filter: (perspective) => 
        console.log(perspective); // check if object is correct
          return true; // return true and not the object as long as you do not want to filter
        
      
    ,
  
);

export  subscriptionManager, pubsub ;

还要检查透视对象是否在 pubsub 调用之前保存和定义。 而且我认为您还想添加订阅应该适用的评论ID。在我这边,它看起来或多或少像post

【讨论】:

我玩过频道定义,但无济于事。但你是对的,这可能是我的服务器的问题。我知道突变被正确调用并且 pubsub.publish() 方法也被执行(我已经在控制台记录了它)。看来问题出在我的订阅解析器上:Subscription: perspectiveAdded(perspective) console.log('did this work?'); return perspective; 那个console.log 没有执行,我得到的错误是订阅解析函数返回未定义 好吧奇怪,你可能想检查你的可执行模式。查看订阅是否在里面。 const executableSchema = makeExecutableSchema( typeDefs: Types, resolvers: Resolvers, logger, allowUndefinedInResolve: false ); 我在 Types up top 中定义了订阅类型和模式类型,但你是说我在这里也需要单独的订阅内容吗? 好吧,很奇怪,当我使用它作为我的解析函数并传入一个 toipcId 作为参数(基本上是评论所属帖子的 ID)时,它解析得很好:Subscription: perspectiveAdded: (root, topicId) => return Perspective.findOne(topicId) 但是看看 Apollo 的例子,他们似乎将整个评论对象传递给 Subscription 解析函数......但我不知道该怎么做 如果可行的话就完美了。如果您查看我添加的帖子,则可以使用根目录。它应该是你的对象

以上是关于Apollo GraphQL 订阅的主要内容,如果未能解决你的问题,请参考以下文章

Apollo graphQL 订阅使用哪个包

Angular Apollo GraphQL watchQuery 与订阅

Apollo - Angular 应用程序中子组件的多个 graphql 订阅

如何在 Apollo 中关闭 GraphQL 订阅的套接字连接

Apollo v2 订阅 graphql

带有 Vertx 订阅的 Apollo GraphQL 失败