嵌套查询/解析器时的 GraphQL.js 订阅响应错误

Posted

技术标签:

【中文标题】嵌套查询/解析器时的 GraphQL.js 订阅响应错误【英文标题】:GraphQL.js Subscription response error when nested queries/resolvers 【发布时间】:2019-04-27 03:37:50 【问题描述】:

我有以下订阅查询工作正常

subscription
  streamShipmentOrder
    id
  

但以下发送“无法读取未定义的属性'ShipmentOrder'”错误

subscription
  streamShipmentOrder
    id
    logs
      comment
    
  

这是我的 ShipmentOrder 类型定义,我使用sequelize 与数据库对话

const ShipmentOrderType = new GraphQLObjectType(
    name: 'ShipmentOrder',
    fields: () => (
       id:  type: GraphQLID ,
       logs: 
          type: new GraphQLList(LogType),
          resolve: async (parent, args,  models , info) => 
             return await models.ShipmentOrder.findOne(
                where:  id: parent.id ,
                include: [ model: models.Log ],
             ).then((data) => data.logs);
          
       ,
    

这里是订阅定义

const ShipmentOrderSubscription = new GraphQLObjectType(
   name: 'Subscription',
   fields: () => (
      streamShipmentOrder: 
         type: ShipmentOrderType,
         resolve: (payload) => payload.shipmentOrderData,
         subscribe: () =>
            socket.asyncIterator([
               SHIPMENT_ORDER_CREATED,
               SHIPMENT_ORDER_UPDATED,
               SHIPMENT_ORDER_DELETED
            ]),
      ,
   ),
);

以及触发订阅的突变,(在请求嵌套结果时,突变也可以正常工作)

const ShipmentOrderMutation = new GraphQLObjectType(
    name: 'Mutation',
    fields: () => (
        createShipmentOrder: 
            type: ShipmentOrderType,
            args: ...,
            resolve: async (parent, args,  models , info) => 

                // create shipmentOrder
                return await models.ShipmentOrder.create(...)
                    .then(async (createdShipmentOrder) => 

                    // create log and relate to created shipmentOrder
                    await models.Log.create(...);

                    // get created shipmentOrder with its logs
                    return await models.ShipmentOrder.findOne(
                        where:  id: createdShipmentOrder.id ,
                        include: [ model: models.Log ],
                    ).then((foundShipmentOrder) => 

                        // updates streams
                        socket.publish(SHIPMENT_ORDER_CREATED, 
                            shipmentOrderData: foundShipmentOrder,
                        );
                        return foundShipmentOrder;

                    );
                
            
        
    )
);

我可能会错过什么?

【问题讨论】:

推测,modelslogs 字段的解析器中未定义。您如何在该文件中导入models?该对象是如何导出的?您是否使用此处概述的“关联”模式 (github.com/sequelize/express-example) 来防止循环依赖? 是的@DanielRearden,关联适用于所有其他查询和突变,当仅询问主要类型时,每个订阅也适用,只有在询问其他“子属性”或关系时才会崩溃订阅中的 graphql 响应对象,就像在这个问题案例中一样。 @DanielRearden 你哪里对了! Log 解析器上下文在调用查询和变异时包含 model 对象,但在调用订阅时为空!!我还在想为什么... 【参考方案1】:

正如@DanielRearden 指出的那样,调用订阅时上下文为空,这弄乱了我的关系,这因为上下文在查询/突变和订阅上的处理方式不同.

所以解决的问题是将我的 models 对象添加到 ApolloServer 中 subscriptions 选项的 onConnect 属性,并传递与我相同的对象已经传递给我的上下文选项

const server = new ApolloServer(
    schema,
    subscriptions: 
        onConnect: () => (models),
    ,
    context: () => (models)

【讨论】:

以上是关于嵌套查询/解析器时的 GraphQL.js 订阅响应错误的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Graphql.js 中使用 GraphQL 订阅

GraphQL。如何编写解析器

GraphQL + 中继连接优化

AWS AppSync - 订阅握手期间出错

GraphQL JS 使用 .graphql 文件从节点 js 进行查询

尝试获取库图像选择器时的 Sigbart