6. Implementing query resolvers
4m

In src/resolvers.js, in our tracksForHome , let's add the parameters.

The order of the parameters matters here. If we only added one parameter, then the function would consider it as the first optional parameter: parent. We need the contextValue, which is the third parameter, to access our .

We don't need the first two parameters, so as a convention, we'll name them with underscores: one underscore for the first (parent) and two underscores for the second (args).

For the contextValue, we'll destructure it to access its child object dataSources. And we can omit the fourth parameter, info, as we won't use it.

server/src/resolvers.js
const resolvers = {
Query: {
// get all tracks, will be used to populate the homepage grid of our web client
tracksForHome: (_, __, { dataSources }) => {},
},
};
Code Challenge!

Edit the parameters for the resolver function of the spaceCats field to follow the conventions explained above. You'll need to destructure dataSources from the contextValue parameter. The function should not return anything for now.

From our dataSources object, we'll gain access to our trackAPI (lowercase here as it's the instance of our TrackAPI class extending RESTDataSource) and its getTracksforHome method that we built earlier.

Our tracksForHome will return the results from that TrackAPI method.

server/src/resolvers.js
const resolvers = {
Query: {
// get all tracks, will be used to populate the homepage grid of our web client
tracksForHome: (_, __, { dataSources }) => {
return dataSources.trackAPI.getTracksForHome();
},
},
};
module.exports = resolvers;
Code Challenge!

Create a resolver function for the Query.spaceCats field. Follow the conventions explained above for the four optional parameters. Use the dataSources object to access the spaceCatsAPI.getSpaceCats() method and return the results. Use arrow function syntax.

Now, that takes care of getting the data for our tracks, but we also need the author associated with each track. We need to call the getAuthor method from our TrackAPI.

So where should this call be located? Well, our tracksForHome could map over the returned tracks data, take each track's authorId property, and call getAuthor with it. But then our tracksForHome would always fetch author data, even for queries that don't even request it!

Instead, let's add another specifically for a track's author. To do this, we'll add another key to our resolvers object called Track, indicating that it's for the Track type in our schema. Inside that Track key will be another object with an author , where we'll define our .

server/src/resolvers.js
const resolvers = {
Query: {
// ...
},
Track: {
author: (parent, args, contextValue, info) => {},
},
};

This time we'll need the parent , so let's keep it in the function. We can replace args with an underscore. We'll destructure contextValue to access the dataSources key for our TrackAPI. And then omit info because we don't need it.

server/src/resolvers.js
const resolvers = {
Query: {
// ...
},
Track: {
author: (parent, _, { dataSources }) => {},
},
};

The TrackAPI's getAuthor method needs an authorId. We'll get this value from the parent passed to the . The parent contains data returned by our tracksForHome , and because tracksForHome returns a list, iterates through that list and calls the author once for each track. It passes the current track as the value of parent, enabling us to extract the authorId.

If we were to console.log(parent), inside our author , the printed value would look exactly like a single raw track from the tracks list returned by our RESTDataSource.

Which information will be present in the parent argument of our Track.author resolver?

Let's destructure authorId from the parent . Then, we'll call the getAuthor method from our dataSources.trackAPI method, passing in the authorId. Finally, we'll return the result.

server/src/resolvers.js
const resolvers = {
Query: {
// get all tracks, will be used to populate the homepage grid of our web client
tracksForHome: (_, __, { dataSources }) => {
return dataSources.trackAPI.getTracksForHome();
},
},
Track: {
author: ({ authorId }, _, { dataSources }) => {
return dataSources.trackAPI.getAuthor(authorId);
},
},
};
Code Challenge!

Create a resolver function for the SpaceCat.missions field. Follow the conventions explained above for the four optional parameters. Use the dataSources object to access the spaceCatsAPI.getMissions() method. It takes a catId argument from the parent and returns the results. Use arrow function syntax.

As a best practice, when working on your and , try to keep resolver functions as thin as possible. By doing so, you make your API more resilient to future changes. You can safely refactor your data fetching code, or change the source entirely from a REST API to a database, without breaking your API. This also keeps your resolvers readable and easier to understand, which comes in handy as you define more and more of them!

Now, you might be wondering where the dataSources object that's passed to our comes from. When did we add it to the contextValue parameter? Right now, it isn't added. If we ran our server, it would have no clue about our TrackAPI. It also doesn't know about our yet! Let's make sure all three pieces are connected with each other.

Previous

Share your questions and comments about this lesson

Your feedback helps us improve! If you're stuck or confused, let us know and we'll help you out. All comments are public and must follow the Apollo Code of Conduct. Note that comments that have been resolved or addressed may be removed.

You'll need a GitHub account to post below. Don't have one? Post in our Odyssey forum instead.