This is my introduction to graphQL, and at the moment just a dump of working code
Setup some data
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
const authors = [ { id: 1, firstName: "Tom", lastName: "Coleman" }, { id: 2, firstName: "Sashko", lastName: "Stubailo" }, { id: 3, firstName: "Mikhail", lastName: "Novikov" }, ]; const posts = [ { id: 1, authorId: 1, title: "Introduction to GraphQL", votes: 2 }, { id: 2, authorId: 2, title: "Welcome to Meteor", votes: 3 }, { id: 3, authorId: 2, title: "Advanced GraphQL", votes: 1 }, { id: 4, authorId: 3, title: "Launchpad is Cool", votes: 7 }, ]; const comments = [ { id: 1, postId: 1, content: "this is shit", votes: 2, authorId: 1 }, { id: 2, postId: 2, content: "do you even code?", votes: 3, authorId: 1 }, { id: 3, postId: 2, content: "go to bed", votes: 1, authorId: 1 }, { id: 4, postId: 3, content: "youre tired", votes: 7, authorId: 1 }, ]; |
Setup our type Defs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
const typeDefs = ` type Author { id: Int! firstName: String lastName: String posts: [Post] hello: String comments: [Comment] } type Comment { id: Int! postId: Int content: String votes: Int author: Author } type Post { id: Int! title: String author: Author votes: Int comments: [Comment] } type Query { posts: [Post] author(id: Int!): Author } type Mutation { upvotePost ( postId: Int! ): Post } `; |
Setup our resolvers
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
const resolvers = { Query: { posts: () => posts, author: (parent: any, args: any) => authors.find((author) => author.id === args.id ), }, Author: { posts: author => posts.filter((post) => post.authorId === author.id ), hello: author => "is it me you're looking for?, " + author.firstName, comments: author => comments.filter((comment) => comment.authorId === author.id) }, Post: { author: post => authors.find((author) => author.id === post.authorId ), comments: post => comments.filter((comment) => post.id === comment.postId) }, Comment: { // parent child relationship, define how comment relates to the author author: comment => authors.find((author) => author.id === comment.authorId ), }, Mutation: { upvotePost: (_: any, { postId }: any) => { const post = posts.find(posts, { id: postId }); if (!post) { throw new Error(`Couldn't find post with id ${postId}`); } post.votes += 1; return post; }, }, }; |
Make a executable Schema
1 2 3 4 5 |
import { makeExecutableSchema } from "graphql-tools"; const schema = makeExecutableSchema({ typeDefs, resolvers, }); |
Setup route and enable graphiql
1 2 3 4 5 6 |
import graphqlHTTP from "express-graphql"; app.use("/graphql", graphqlHTTP({ schema: schema, rootValue: resolvers, graphiql: true, })); |
Test out some calls
1 2 3 4 5 6 7 8 9 10 11 12 |
{ author(id: 2) { id firstName lastName posts { title votes comments { content } } }} |
which gives us this result
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
{ "data": { "author": { "id": 2, "firstName": "Sashko", "lastName": "Stubailo", "posts": [ { "title": "Welcome to Meteor", "votes": 3, "comments": [ { "content": "do you even code?" }, { "content": "go to bed" } ] }, { "title": "Advanced GraphQL", "votes": 1, "comments": [ { "content": "youre tired" } ] } ] } } } |
In the real world we will have to make calls to the database, which would cause Nulls being passed around, so lets add in some async await to test (Author for now)
1 2 3 4 5 6 7 |
<em>function</em> getAuthor(<em>id</em>: Int) { return new Promise((<em>resolve</em>) <em>=></em> { return setTimeout(() <em>=></em> { resolve(authors.find((<em>author</em>) <em>=></em> author.id === id)); }, 3000); }); } |
and
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
const resolvers = { Query: { posts: () <em>=></em> posts, author: async (<em>parent</em>: <em>any</em>, <em>args</em>: <em>any</em>) <em>=></em> getAuthor(args.id), }, Author: { posts: <em>author</em> <em>=></em> posts.filter((<em>post</em>) <em>=></em> post.authorId === author.id ), hello: <em>author</em> <em>=></em> "is it me you're looking for?, " + author.firstName, comments: <em>author</em> <em>=></em> comments.filter((<em>comment</em>) <em>=></em> comment.authorId === author.id) }, Post: { author: <em>post</em> <em>=></em> authors.find((<em>author</em>) <em>=></em> author.id === post.authorId ), comments: <em>post</em> <em>=></em> comments.filter((<em>comment</em>) <em>=></em> post.id === comment.postId) }, Comment: { // parent child relationship, define how comment relates to the author author: <em>comment</em> <em>=></em> authors.find((<em>author</em>) <em>=></em> author.id === comment.authorId ), }, Mutation: { upvotePost: (<em>_</em>: <em>any</em>, { <em>postId</em> }: <em>any</em>) <em>=></em> { <em>const</em> post = posts.find(posts, { id: postId }); if (!post) { throw new Error(`Couldn't find post with id ${postId}`); } post.votes += 1; return post; }, }, }; |
Resolver cache ” https://www.youtube.com/watch?v=BM4_IvSjRYw “
https://medium.com/paypal-engineering/graphql-resolvers-best-practices-cd36fdbcef55
https://medium.com/paypal-engineering/graphql-resolvers-best-practices-cd36fdbcef55
Leave a Reply