2017-10-24 2 views
1

Ich bin ziemlich neu zu GraphQl und ich folgte dem GraphQL NodeJS Backend-Tutorial hier: GraphQL Realtime Subscriptions. Alles hat gut funktioniert und ich habe das Tutorial abgeschlossen. Als nächstes folgte ich dem VueJS mit Apollo-Frontend-Tutorial hier: Vue & Apollo Subscriptions. Ich habe mich entschieden, meinen eigenen erstellten GraphQL-Server aus dem ersten Tutorial zu verwenden, anstatt GraphCool zu verwenden, das im Frontend-Tutorial verwendet wird. Dies ist der Teil, wo ich feststecke. Wenn ichFehler im Abonnement GraphQL Server

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

im GraphiQL Client aufrufen bekomme ich die id, url und description, wenn ich einen neuen Link in einem anderen Browser-Tab erstellen mit den Daten data: Link: node: {id: "59ef0bbeef32bb05692ee4b4", url: "http://new-test-url2.com", description: "Test description2"} (Dieses Abonnement Aufruf auch im Backend vorgenommen wird Anleitung). Aber wenn ich

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

ich den Fehler:

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

mit den Daten data:{Link: {node: null}}

Ich kann einfach nicht die Antwort auf dieses Problem finden. Hoffentlich kann mir jemand dabei helfen. Dies ist mein Code:

schema/index.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 
} 

schema/resolvers.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(); 
    }, 
}, 

Antwort

1

der Hoffnung, Sie in der Lage waren, diese zu lösen, da es so lange gewesen ist, Ich habe das heute selbst herausgefunden. Das Problem hierbei ist, dass der Subskriptionsserver niemals im Kontext übergeben wurde, dh die Dataloader/Benutzerinformationen.

In dieser Lektion (https://www.howtographql.com/graphql-js/4-connectors/) Sie Setup der Kontext für den Express-Server, aber das war nie den Abonnement-Server hinzugefügt:

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

Um dies zu dem Subskriptions-Server hinzuzufügen ich diese Optionen selbst verwendet :

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

ich dann dies, indem einfach auf die SubscriptionServer hinzugefügt, um die onConnect Parameter hinzu:

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}.`)       
}); 

Und das sollte meist alles funktionieren. Ich persönlich mache das rectjs-Tutorial, also bin ich mir nicht sicher, welche individuellen Probleme es dafür geben wird, aber die reactsjs Tutorial-API-Aufrufe waren durchgehend ein wenig nicht synchron.

+0

Vielen Dank! Es funktionierte! Ich hörte auf, es zu versuchen, weil ich es satt hatte, aber du hast gerade meinen Tag gemacht. – BramH