代码之家  ›  专栏  ›  技术社区  ›  Pixeldenker

订阅GraphQL服务器出错

  •  1
  • Pixeldenker  · 技术社区  · 7 年前

    我对GraphQl相当陌生,我在这里学习了GraphQl NodeJS后端教程: GraphQL Realtime Subscriptions . 一切都很顺利,我完成了教程。 接下来,我在这里学习了VueJS和Apollo前端教程: Vue & Apollo Subscriptions . 我选择使用第一个教程中自己创建的GraphQL服务器,而不是使用前端教程中使用的GraphTool。这就是我被困的地方。

    subscription {
        Link(filter: {
          mutation_in: [CREATED]
        }) {
          node {
            id
            url
            description
          }
        }
    }
    

    在GraphiQL客户端中,我确实得到了 id , url description 当我用数据在不同的浏览器选项卡中创建新链接时 data: Link: node: {id: "59ef0bbeef32bb05692ee4b4", url: "http://new-test-url2.com", description: "Test description2"} (此订阅调用也在后端教程中进行)。但是当我打电话的时候

    subscription {
        Link(filter: {
          mutation_in: [CREATED]
        }) {
          node {
            id
            url
            description
            postedBy {
              id
              name
            }
            votes {
              id
              user {
                 id
              }
            }
          }
        }
      }
    

    我得到错误:

    {message: "Cannot destructure property `Users` of 'undefined' or 'null'.",…}
    {message: "Cannot destructure property `Votes` of 'undefined' or 'null'.",…}
    

    使用数据 data:{Link: {node: null}}

    我就是找不到这个问题的答案。希望有人能帮我。 这是我的代码:

    架构/索引。js公司

    type Link {
        id: ID!
        url: String!
        description: String!
        postedBy: User
        votes: [Vote!]!
    }
    
    type User {
        id: ID!
        name: String!
        email: String!
        password: String!
        votes: [Vote!]!
    }
    
    type Vote {
        id: ID!
        user: User!
        link: Link!
    }
    
    type SigninPayload {
        token: String
        user: User
    }
    
    type Query {
        allLinks(filter: LinkFilter, skip: Int, first: Int): [Link!]!
    }
    
    type Mutation {
        createLink(url: String!, description: String!): Link
    
        createVote(linkId: ID!): Vote
    
        createUser(name: String!, email: String!, password: String!): User
    
        signinUser(email: String!, password: String!): SigninPayload!
    }
    
    type Subscription {
        Link(filter: LinkSubscriptionFilter): LinkSubscriptionPayload
        Vote(filter: VoteSubscriptionFilter): VoteSubscriptionPayload
    }
    
    input LinkSubscriptionFilter {
        mutation_in: [_ModelMutationType!]
    }
    
    input VoteSubscriptionFilter {
        mutation_in: [_ModelMutationType!]
    }
    
    type LinkSubscriptionPayload {
        mutation: _ModelMutationType!
        node: Link
    }
    
    type VoteSubscriptionPayload {
        mutation: _ModelMutationType!
        node: Vote
    }
    
    input LinkFilter {
        OR: [LinkFilter!]
        description_contains: String
        url_contains: String
    }
    
    enum _ModelMutationType {
        CREATED
        UPDATED
        DELETED
    }
    

    模式/解析器。js:

    Query: {
        allLinks: async (root, {filter, first, skip}, {mongo: {Links, Users}}) => {
            let query = filter ? {$or: buildFilters(filter)} : {};
            const cursor = Links.find(query);
            if (first) {
                cursor.limit(first);
            }
    
            if (skip) {
                cursor.skip(skip);
            }
    
            return cursor.toArray();
        },
    },
    
    Mutation: {
        createLink: async (root, data, {mongo: {Links}, user}) => {
    
            assertValidLink(data);
            const newLink = Object.assign({postedById: user && user._id}, data);
            const response = await Links.insert(newLink);
    
            newLink.id = response.insertedIds[0];
    
            pubsub.publish('Link', {Link: {mutation: 'CREATED', node: newLink}});
    
            return newLink;
        },
    
        createUser: async (root, data, {mongo: {Users}}) => {
            const newUser = {
                name: data.name,
                email: data.email,
                password: data.password,
            };
    
            const response = await Users.insert(newUser);
    
            return Object.assign({id: response.insertedIds[0]}, newUser);
        },
    
        createVote: async (root, data, {mongo: {Votes}, user}) => {
            const newVote = {
                userId: user && user._id,
                linkId: new ObjectID(data.linkId),
            };
    
            const response = await Votes.insert(newVote);
    
            return Object.assign({id: response.insertedIds[0]}, newVote);
        },
    
        signinUser: async (root, data, {mongo: {Users}}) => {
            const user = await Users.findOne({email: data.email});
            if (data.password === user.password) {
                return { token: `token-${user.email}`, user };
            }
        },
    },
    
    Subscription: {
        Link: {
            subscribe: () => pubsub.asyncIterator('Link'),
        },
    },
    
    Link: {
        id: root => root._id || root.id,
    
        // postedBy: async ({postedById}, data, {dataloaders: {userLoader}}) => {
        //     return await userLoader.load(postedById);
        // },
    
        postedBy: async ({postedById}, data, {mongo: {Users}}) => {
            return await Users.findOne({_id: postedById});
        },
    
        votes: async ({_id}, data, {mongo: {Votes}}) => {
            return await Votes.find({linkId: _id}).toArray();
        },
    },
    
    1 回复  |  直到 7 年前
        1
  •  2
  •   Marii    7 年前

    希望你们能解决这个问题,因为它已经很长时间了,我今天才自己解决了这个问题。这里的问题是,订阅服务器从未在上下文中传递,即数据加载程序/用户信息。

    在本课中( https://www.howtographql.com/graphql-js/4-connectors/ )您为express server设置了上下文,但从未将其添加到订阅服务器:

      const buildOptions = async (req,res) => {                                                     
    const user = await authenticate(req, mongo.Users)                                           
    return {                                                                                    
      context: {                                                                                
        dataloaders: buildDataloaders(mongo),                                                   
        mongo,                                                                                  
        user                                                                                    
      },                                                                                        
      formatError,                                                                              
      schema,                                                                                   
    }                                                                                           
    

    const subscriptionBuildOptions = async (connectionParams,webSocket) => 
    {                      
      return {                                                                                   
        dataloaders: buildDataloaders(mongo),                                                    
        mongo,                                                                                   
      }
    }  
    

    然后,我通过简单地添加onConnect参数将其添加到SubscriptionServer:

    const server = createServer(app);                                                             
    server.listen(PORT, () => {                                                                   
      SubscriptionServer.create(                                                                  
        {execute, subscribe, schema, onConnect: subscriptionBuildOptions},                        
        {server, path: '/subscriptions'},                                                         
      );                                                                                          
      console.log(`Hackernews GraphQL server running on port ${PORT}.`)                           
    }); 
    

    这应该能让一切正常运作。我个人正在做reactjs教程,所以不确定会有哪些个别问题,但reactjs教程api调用始终有点不同步。