Slide 1

Slide 1 text

A Gentle Introduction to Resolvers Steve Kinney

Slide 2

Slide 2 text

@stevekinney Hi, I’m Steve. (@stevekinney)

Slide 3

Slide 3 text

@stevekinney What even is a resolver? • Short answer: It’s a function or method that resolves a value for a type or field in your schema. • Every field on every type is backed by a function called a resolver.

Slide 4

Slide 4 text

@stevekinney Resolving values and objects • If the return value of a function is a literal (e.g. a string or a number or a boolean). Cool, we’re done here. • Otherwise, if it’s an object, we’re going to dip down into that object and try to resolve it as well. • We’ll keep diving deeper until we’ve gotten to the bottom of things.

Slide 5

Slide 5 text

Play: https://graph-jukebox.glitch.me/ Edit: https://glitch.com/edit/#!/graph-jukebox type Artist { id: Int name: String } type Query { artists: [Artist!] }

Slide 6

Slide 6 text

Play: https://graph-jukebox.glitch.me/ Edit: https://glitch.com/edit/#!/graph-jukebox query { artists { id name } }

Slide 7

Slide 7 text

Play: https://graph-jukebox.glitch.me/ Edit: https://glitch.com/edit/#!/graph-jukebox const resolvers = { Query: { artists() { return [{ id: 1, name: 'The National' }]; } } };

Slide 8

Slide 8 text

@stevekinney Resolvers can be asynchronous.

Slide 9

Slide 9 text

Play: https://graph-jukebox.glitch.me/ Edit: https://glitch.com/edit/#!/graph-jukebox const resolvers = { Query: { artists() { return [...artists]; }, albums() { return new Promise(resolve => resolve([...albums])); }, songs() { return axios.get(‘/some-endpoint') .then(response => response.data); } } };

Slide 10

Slide 10 text

@stevekinney Siblings are executed in parallel.

Slide 11

Slide 11 text

@stevekinney Query Artists Albums ID Name Title Year ID

Slide 12

Slide 12 text

@stevekinney If a resolver returns a promise, we’re obviously going to have to—umm— resolve wait for it before diving down.

Slide 13

Slide 13 text

@stevekinney Query Artists Albums ID Name Title Year ID

Slide 14

Slide 14 text

@stevekinney

Slide 15

Slide 15 text

@stevekinney We should probably use GraphQL for this problem, right? • A user might want to pull up all of the artists in their library with their albums. • They might just want to see a list of albums. • Or, maybe, they just want to a big ol’ list of songs. • (We’re going to ignore playlists for now.)

Slide 16

Slide 16 text

@stevekinney What might our schema look like?

Slide 17

Slide 17 text

Play: https://graph-jukebox.glitch.me/ Edit: https://glitch.com/edit/#!/graph-jukebox type Artist { id: Int name: String albums: [Album] songs: [Song] }

Slide 18

Slide 18 text

Play: https://graph-jukebox.glitch.me/ Edit: https://glitch.com/edit/#!/graph-jukebox type Album { id: Int title: String year: Int artist: Artist songs: [Song] }

Slide 19

Slide 19 text

Play: https://graph-jukebox.glitch.me/ Edit: https://glitch.com/edit/#!/graph-jukebox type Song { id: Int title: String time: Int artist: Artist album: Album }

Slide 20

Slide 20 text

Play: https://graph-jukebox.glitch.me/ Edit: https://glitch.com/edit/#!/graph-jukebox type Query { artists: [Artist!] albums: [Album!] songs: [Song!] artist(id: Int!): Artist! album(id: Int!): Album! song(id: Int!): Song! } type Mutation { addArtist(name: String!): Artist addAlbum(title: String!, year: Int, artistId: Int): Album addSong(title: String!, time: Int, artistId: Int, albumId: Int): Song }

Slide 21

Slide 21 text

@stevekinney Let’s talk about our data.

Slide 22

Slide 22 text

Play: https://graph-jukebox.glitch.me/ Edit: https://glitch.com/edit/#!/graph-jukebox [ { "id": 1, "name": "The National" }, { "id": 2, "name": "Camp Cope" }, { "id": 3, "name": "Rilo Kiley" } ]

Slide 23

Slide 23 text

Play: https://graph-jukebox.glitch.me/ Edit: https://glitch.com/edit/#!/graph-jukebox [ { "id": 1, "artistId": 1, "title": "Trouble Will Find Me", "year": 2013 }, { "id": 2, "artistId": 2, "title": "How to Socialize and Make Friends", "year": 2018 } ]

Slide 24

Slide 24 text

Play: https://graph-jukebox.glitch.me/ Edit: https://glitch.com/edit/#!/graph-jukebox [ { "title": "Done", "time": "4:47", "artistId": 2, "albumId": 5, "id": 1 }, { "title": "Flesh & Electricity", "time": "3:57", "artistId": 2, "albumId": 5, "id": 2 }, { "title": "West Side Story", "time": "5:32", "artistId": 2, "albumId": 5, "id": 3 }, ]

Slide 25

Slide 25 text

@stevekinney Alright, let’s get into writing a resolver.

Slide 26

Slide 26 text

@stevekinney Resolver functions get four arguments. • root or parent • args • context • info

Slide 27

Slide 27 text

Play: https://graph-jukebox.glitch.me/ Edit: https://glitch.com/edit/#!/graph-jukebox const resolvers = { Query: { artists() { return [{ id: 1, name: 'The National' }]; } } };

Slide 28

Slide 28 text

Play: https://graph-jukebox.glitch.me/ Edit: https://glitch.com/edit/#!/graph-jukebox const resolvers = { Query: { artists(root, args, context, info) { return [{ id: 1, name: 'The National' }]; } } };

Slide 29

Slide 29 text

@stevekinney So, when would you use args?

Slide 30

Slide 30 text

Play: https://graph-jukebox.glitch.me/ Edit: https://glitch.com/edit/#!/graph-jukebox type Query { artists: [Artist!] artist(id: Int!): Artist! }

Slide 31

Slide 31 text

Play: https://graph-jukebox.glitch.me/ Edit: https://glitch.com/edit/#!/graph-jukebox query { artist(id: 1) { id name } }

Slide 32

Slide 32 text

Play: https://graph-jukebox.glitch.me/ Edit: https://glitch.com/edit/#!/graph-jukebox const resolvers = { Query: { // … artist(root, args) { return artists.find(artist => artist.id === args.id); } // … } };

Slide 33

Slide 33 text

@stevekinney What about descending down the tree?

Slide 34

Slide 34 text

Play: https://graph-jukebox.glitch.me/ Edit: https://glitch.com/edit/#!/graph-jukebox type Artist { id: Int name: String albums: [Album] songs: [Song] }

Slide 35

Slide 35 text

Play: https://graph-jukebox.glitch.me/ Edit: https://glitch.com/edit/#!/graph-jukebox Query: { // … Artist: { albums(artist) { // artist is the parent value return albums.filter(album => album.artistId === artist.id); }, songs(artist) { return songs.filter(song => song.artistId === artist.id); } }, // … } };

Slide 36

Slide 36 text

@stevekinney By default, resolvers will look to see if whatever you’re looking for is a property on the object.

Slide 37

Slide 37 text

Play: https://graph-jukebox.glitch.me/ Edit: https://glitch.com/edit/#!/graph-jukebox const resolvers = { Artist: { // You don't need to do this. name(artist) { return artist.name; }, albums(artist) { return albums.filter(album => album.artistId === artist.id); }, songs(artist) { return songs.filter(song => song.artistId === artist.id); } } };

Slide 38

Slide 38 text

And now… @stevekinney Mutations

Slide 39

Slide 39 text

Play: https://graph-jukebox.glitch.me/ Edit: https://glitch.com/edit/#!/graph-jukebox const resolvers = { Mutation: { addArtist(_, args) { const artist = { ...args, id: generateId() }; artists.push(artist); return artist; } } };

Slide 40

Slide 40 text

Play: https://graph-jukebox.glitch.me/ Edit: https://glitch.com/edit/#!/graph-jukebox const resolvers = { Mutation: { addArtist(_, args) { return axios.post('/artists', args) .then(response => response.data); } } };

Slide 41

Slide 41 text

And now… @stevekinney What about context?

Slide 42

Slide 42 text

@stevekinney What is context? • Short answer: It’s an object shared by all of the resolvers. • It's mutable. • It's destroyed between every request.

Slide 43

Slide 43 text

@stevekinney What might you store in context? • Authentication data • The request object in something like Express • API fetching functions • Database connections

Slide 44

Slide 44 text

Play: https://graph-jukebox.glitch.me/ Edit: https://glitch.com/edit/#!/graph-jukebox const server = new ApolloServer({ typeDefs, resolvers, context: ({ req }) => ({ authScope: getScope(req.headers.authorization) }) }); // Resolver (root, args, context) => { if (context.authScope !== ADMIN) { throw AuthenticationError('not admin'); } // More stuff… };

Slide 45

Slide 45 text

@stevekinney Let’s poke around the working version of the application, shall we? • https://glitch.com/edit/#!/graph-jukebox • Let’s look at how to add additional properties. • Let’s look at an example that makes AJAX requests.

Slide 46

Slide 46 text

@stevekinney Fin.