9. Resolvers & data sources
5m

Overview

are responsible for returning data for a specific in our schema. So far, we've returned hard-coded playlist data but it's time to replace that with a call to our REST API.

In this lesson, we will:

  • Learn how to access from a function
  • Use an HttpClient to make a REST API call to an endpoint
  • Convert HTTP response types to what our and schema expects

Resolvers

So far, we've written functions that don't require any parameters. For example, the Query.Hello immediately returned a string value "Hello World".

We also had our property for a playlist's Id, Name and Description, where each 's get accessor acted as the function.

But can do much more! A resolver can accept the following parameters:

  • Values for arguments. are used to identify, filter, or transform data. We'll cover this in the next lesson.
  • The parent value. We'll also cover this in a later lesson.
  • HttpContext. The context involved in the HTTP request sent to the server.
  • Data sources (or services). The services we registered with the server using dependency injection.

In this lesson, we'll focus on the parameter.

Accessing data sources

In the previous lesson, we registered the SpotifyService with our so that we could access it in the functions.

In Query.cs, let's make use of the SpotifyService by adding it as a parameter inside the FeaturedPlaylists function.

Query.cs
public List<Playlist> FeaturedPlaylists(SpotifyService spotifyService)

Make sure we're importing the SpotifyWeb package at the top as well, where SpotifyService lives (otherwise, you'll see an error!).

Query.cs
using SpotifyWeb;

That's it! We can use the spotifyService instance anywhere in our function body.

In the previous lesson, we did one extra step and used RegisterService<SpotifyService> in our , which was optional. If we didn't do that, our function would look like this instead:

Query.cs
public List<Playlist> FeaturedPlaylists([Service] SpotifyService spotifyService)

We would have needed to include the [Service] attribute with the SpotifyService to access it! Isn't it much cleaner to omit it? We think so!

GetFeaturedPlaylists

Tip: Make use of your code editor's IntelliSense features to get insight into what methods are available from the spotifyService!

Now that we can access the spotifyService, we can make our first HTTP call and store the response.

Query.cs
var response = spotifyService.GetFeaturedPlaylistsAsync();

The GetFeaturedPlaylistsAsync method maps to the GET /browse/featured-playlists endpoint we were exploring earlier.

This method is asynchronous, so we'll await the results and mark the function as async. With an asynchronous function, the return type needs to be a Task<T> type as well.

Query.cs
public async Task<List<Playlist>> FeaturedPlaylists(SpotifyService spotifyService)
{
var response = await spotifyService.GetFeaturedPlaylistsAsync();
// return new List<Playlist>{...};
}

Hovering over the response , we can see that its type is SpotifyWeb.FeaturedPlaylists. That's the response type we saw earlier (in the REST API docs) with the top-level properties of message and playlists. It's not what this function should return. Instead, we have to access response.Playlists.Items.

Query.cs
var items = response.Playlists.Items;

Now the items is a collection of PlaylistSimplified types (this type is defined in SpotifyWeb). It's not quite a Playlist type, but it does contain the properties we need to convert it into a Playlist type!

To convert a PlaylistSimplified type to a Playlist type, we'll creating an additional new constructor inside the Playlist class.

Open up Playlist.cs and create a new constructor that takes in a PlaylistSimplified object and sets each Playlist property using the object's properties.

Playlist.cs
public Playlist(PlaylistSimplified obj)
{
Id = obj.Id;
Name = obj.Name;
Description = obj.Description;
}

Don't forget to import the SpotifyWeb namespace at the top, since PlaylistSimplified is coming from that package (better yet, let your code editor do that auto-import for you!)

Playlist.cs
using SpotifyWeb;

Now we can use this constructor back in the Query.FeaturedPlaylists . We'll use the Select function to map over each PlaylistSimplified object in the items collection and return a new Playlist object.

Query.cs
var playlists = items.Select(item => new Playlist(item));

Finally, we need to convert the collection into a list using ToList() so it matches that List<Playlist> type the wants to return!

Query.cs
return playlists.ToList();

Perfect! Feel free to bring all that into one clean line.

Query.cs
return response.Playlists.Items.Select(item => new Playlist(item)).ToList();

And we're good to remove the hard-coded Playlist objects from before.

Query.cs
- return new List<Playlist>
- {
- new Playlist("1", "GraphQL Groovin'"),
- new Playlist("2", "Graph Explorer Jams"),
- new Playlist("3", "Interpretive GraphQL Dance")
- };

Explorer time!

Excited to see what all that code did?! Make sure all files have been saved and the server is running with the latest changes.

Let's jump over to Sandbox Explorer and run that same for featured playlists.

GraphQL operation
query FeaturedPlaylists {
featuredPlaylists {
id
name
description
}
}

Look at that! We've got our featured playlists coming back from a REST API data source

https://studio.apollographql.com/sandbox/explorer

Response data

Comparing with the REST approach

Let's put on our product app developer hat on for a minute and compare what this feature would have looked like if we had used REST instead of .

If we had used REST, the app logic would have included:

  • Making the HTTP GET call to the /browse/featured-playlists endpoint
  • Digging into the response JSON's playlists.items property
  • Retrieving just the id, name and description properties, discarding all the rest of the response.

There's so much more to the response that wasn't used! If the client app had slow network speeds or not much data, that big response comes with a cost.

With , we have our short and sweet, clean, readable coming from the client, coming back in exactly the shape they specified, no more, no less!

All the logic of extracting the data and filtering for which are needed are all done on the side.

Note: As you can see, REST and can work together! Learn more about this dynamic in this video "GraphQL and REST: true BFFs - Dan Boerner / API World".

Practice

What parameters can a resolver function accept?

Key takeaways

  • functions can accept parameters such as values for , the parent value, HttpContext, and .
  • By consuming a API instead of a REST API, we avoid dealing with large response data.

Up next

Exciting progress! But you're probably thinking — what are playlists without songs? 🎵 In the next few lessons, we'll tackle the next feature: a playlist's tracks.

Previous

Share your questions and comments about this lesson

This course is currently in

beta
. 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.