"message":"Cannot read properties of undefined (reading 'asyncIterator')",在阿波罗工作室

"message": "Cannot read properties of undefined (reading 'asyncIterator')", in Apollo Studio

我在 Apollo Studio 中提交订阅时收到以下响应,我正在失去理智调试!我似乎找不到问题。

通常在执行 server.installSubscriptionHandlers() 时一切都会正常,但现在在 Apollo 版本 3 中,根据文档,事情必须以不同的方式完成。 在这里阅读更多:https://www.apollographql.com/docs/apollo-server/data/subscriptions/

我的包裹:

"graphql-subscriptions": "^2.0.0",
"graphql-tools": "^4.0.8",
"subscriptions-transport-ws": "^0.11.0",
"apollo-server-express": "^3.5.0",
"express": "^4.17.2",

ApolloStudio 中的响应:

{
  "errors": [
    {
      "message": "Cannot read properties of undefined (reading 'asyncIterator')",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ],
      "path": [
        "newTodo"
      ]
    }
  ]
}

我在 ApolloStudio 中输入的内容:

subscription {
  newTodo {
    description
    id
    title
  }
}

我的相关解析器代码:

const NEW_TODO = "NEW_TODO";

const resolvers: IResolvers = {
//...
Mutation: {
        addTodo: async (
            parent,
            args: null,
            { pubsub },
            info: any
        ): Promise<Todo> => {
            const newTodo: Todo = {
               id: v4(),
               title: "New Todo!",
               description: "New Todo, Wohoo" 
            }
            todos.push(newTodo);
            pubsub.publish(NEW_TODO, { newTodo });
            return todos[todos.length - 1];
        }
    },
    Subscription: {
        newTodo: {
            subscribe: (_, __, {pubsub}) => pubsub.asyncIterator(NEW_TODO),
        },
    }
}

我的类型定义:

type Subscription {
    newTodo: Todo!
}

我的服务器:


//...

const pubsub = new PubSub();

const apolloServer = new ApolloServer({
    schema,
    context: ({req, res}): any => ({req, res, pubsub}),
    plugins: [{
        serverWillStart: async () => {
            return {
                async drainServer() {
                    subscriptionServer.close();
                }
            }
        }
    }],
});

(async function() {
    await apolloServer.start();
    apolloServer.applyMiddleware({ app, cors: true }); 
})();

const httpServer = createServer(app);
const subscriptionServer = new SubscriptionServer({
    schema,
    execute, 
    subscribe,
    onConnect() {
        console.log("SubscriptionServer ready!");
    },
}, {
    server: httpServer,
    path: "/graphql"
});

//...

正如@Jared Smith 所说,subscribe() 没有接收到 pubsub 存在问题,所以我通过访问服务器代码并将 const pubsub 更改为 export const pubsub 然后我将它导入解析器。似乎是一个不优雅的解决方案,但它现在可以完成工作!

我通过使用 useServer 在 websocket 服务器上设置上下文来解决它,查询和突变似乎与订阅有不同的上下文,这是我的代码

(async () => {
    const app = express();
    const httpServer = createServer(app);
    const pubsub = new PubSub();

    app.use(cors());

    const schema = makeExecutableSchema({ typeDefs, resolvers});

    const wsServer = new WebSocketServer({
        server: httpServer,
        path: '/graphql',
    })

    const serverCleanup = useServer({ 
        schema, 
        context: (ctx, msg, args) => ({ pubsub }), // <-- SOLVES IT
        }, wsServer);

    const apolloServer = new ApolloServer({
        schema,
        context: ({ req, res }: any) => ({req, res, pubsub}),
        plugins: [
            ApolloServerPluginDrainHttpServer({ httpServer }),
            {
                async serverWillStart() {
                    return {
                        async drainServer(){
                            await serverCleanup.dispose();
                        },
                    };
                }
            },
        ],
    });
    
    await apolloServer.start();

    apolloServer.applyMiddleware({ app, cors: false });

    httpServer.listen({ port: 8000 }, () => {
        console.log(
            ` Query endpoint ready at http://localhost:8000${apolloServer.graphqlPath}`
        );
        console.log(
            ` Subscription endpoint ready at ws://localhost:8000${apolloServer.graphqlPath}`
        );
    });
})()