Overview
Onwards with our next feature!
In this lesson, we will:
- Learn about GraphQL arguments and how to access them in a resolver function
- Learn how to use GraphQL variables in an operation
The mockup
Here's our next feature: the playlist page.
We'll most likely get to this page through a few ways: clicking on a specific playlist from the featured playlists page or maybe directly through a URL link.
However we get to this page, we'll need the playlist ID, which makes it a perfect use case for a GraphQL argument.
GraphQL arguments
An argument is a value you provide for a particular field in your query.
Resolvers can use a field's provided arguments to help determine how to populate the data for that field. Arguments can help retrieve specific objects, filter through a set of objects, or even transform the field's returned value. For example, a query that performs a search usually provides the user's search term as an argument.
A new entry point
Our schema evolves again! We're adding a new entry point.
Inside the Query
class, we'll add a new resolver called playlist
, which returns a nullable Playlist
type. We're making this nullable because it's possible that the playlist we're looking for doesn't exist (for example, it may have been deleted).
This resolver will be async
and we'll apply the strawberry.field
as a decorator.
@strawberry.fieldasync def playlist(self) -> Playlist | None:...
Remember, adding self
as an argument inside the resolver function is good practice.
We'll also add another parameter: id
of type strawberry.ID
to denote that this should be of type ID
in GraphQL.
Note that the id
parameter can be named anything, like playlist_id
for example! We recommend collaborating with your team to decide on naming conventions. Using id
as the GraphQL argument name is a common convention.
@strawberry.fieldasync def playlist(self,id: strawberry.ID) -> Playlist | None:...
We'll also include the info
parameter, which we'll use later on to access spotify_client
:
@strawberry.fieldasync def playlist(self,id: strawberry.ID,info: strawberry.Info) -> Playlist | None:...
At the top of the file, let's import the function to fetch a playlist from the mock_spotify_rest_api_client
package, called get_playlist
.
from mock_spotify_rest_api_client.api.playlists import get_playlist
Now jumping back to the playlist
resolver, let's use this function to fetch the playlist data from the REST API. We'll pass in the same spotify_client
value, as well as the id
argument for the playlist_id
parameter the function is expecting.
Similar to the featured_playlists
resolver, we'll await
the results and store them in a data
variable.
spotify_client = info.context["spotify_client"]data = await get_playlist.asyncio(client=spotify_client, playlist_id=id)
If data
is None
, this most likely means there wasn't a playlist with that particular ID. We'll return None
in this case.
if data is None:return None
This resolver needs to return a Playlist
type, but data
(if it isn't None
) is a SpotifyObjectPlaylist
type.
So let's create a new Playlist
object with the data properties we do have have, and return it.
return Playlist(id=strawberry.ID(data.id),name=data.name,description=data.description,)
Don't forget the GraphQL description for the resolver! We can add that to the @strawberry.field
decorator,
@strawberry.field(description="Retrieves a specific playlist.")
Let's save our changes and make sure our server is still running successfully with no problems.
Explorer time!
Time to see how our GraphQL schema has evolved with those changes! Let's jump back to Sandbox and create a new workspace.
In the Explorer page, navigating back to the root Query
type in the Documentation panel, we can see a new field: the playlist(...)
field.
Click on the + button beside "Fields" to add all three playlist fields to the operation.
query Playlist($playlistId: ID!) {playlist(id: $playlistId) {idnamedescription}}
We'll notice something new here: a dollar sign ($
) followed by the name playlistId
.
Variables
The $
symbol indicates a variable in GraphQL. The name after the $
symbol is the name of our variable, which we can use throughout the query. After the colon is the variable's type, which must match the type of the argument we'll use it for.
Variables are great—they let us pass argument values dynamically from the client-side so we don't have to hardcode values into our query. We'll use them every time we create a query with arguments.
In our case, we have a variable called playlistId
that the Explorer set up for us down in the Variables section. Right now, it's set to null
.
If we try to run the query now, we'll still get a JSON object back, but this time with an errors
key, instead of data
:
{"errors": [{"message": "Variable `playlistId` is required.","locations": [{"line": 1,"column": 16}],"extensions": {"code": "HC0018","variable": "playlistId"}}]}
This lets us know that we can't leave the playlistId
as null
, because the schema specifically defines the id
argument (where we're using the playlistId
variable) as a non-nullable type!
Let's go ahead and update the null
value to a playlist ID we know exists from the featuredPlaylists
query.
{"playlistId": "6Fl8d6KF0O4V5kFdbzalfW"}
Lastly, we'll rename the operation to be a bit more descriptive — like GetPlaylistDetails
.
query GetPlaylistDetails($playlistId: ID!) {playlist(id: $playlistId) {idnamedescription}}
Run the query to get the details of the Sweet Beats & Eats
playlist!
Practice
Playlist
type returned from the playlist
resolver marked as nullable?Key takeaways
- Arguments are values provided for a particular field in a GraphQL query. Resolvers use field arguments to determine how to populate data for that field.
- The
$
symbol indicates a variable in GraphQL. The name after the$
symbol is the name of our variable, which we can use throughout the query. After the colon is the variable's type, which must match the type of the argument we'll use it for.
Up next
We hear you, you're ready for some jams! We'll add the playlist's tracks in the next lesson.
Share your questions and comments about this lesson
This course is currently in
You'll need a GitHub account to post below. Don't have one? Post in our Odyssey forum instead.