Executing GraphQL Queries
GraphQL is surging in popularity as a preferred choice for APIs over REST APIs. One of the reasons many companies cite for converting their APIs from REST to GraphQL is its ease of use. If you know JSON, GraphQL is incredibly intuitive. And there are helpful tools like GraphiQL, an in browser GraphQL IDE.
Even with its usability, there are still a few pointers which are helpful to learning GraphQL. GitHub implemented their API v4 using GraphQL. Let’s work through an example using GitHub’s GraphiQL explorer to hit the GitHub API as a way to learn some basic GraphQL:
GraphiQL Keyboard Shortcuts
Before we start, take a look at these keyboard shortcuts I frequently use when working in the GraphiQL IDE:
- Auto Complete: Ctrl-Space (or Option-Space)
- Run query: Ctrl-Enter
- Format query: Ctrl-Shift-P
GitHub’s GraphiQL Explorer
When you open up GitHub’s GraphiQL explorer, you’ll see three panes. The top left is a query editor for our GraphQL query to GitHub’s API; bottom left is for query variables; and the right side will display query results when we hit the API.
After signing in with your GitHub account details, Hit play (Ctrl-Enter) on the query which GitHub autofills! You’ll see your login displayed on the right side of the screen. The first item to note here is that the result mirrors the syntax and format of the query. This is a big part of what makes GraphQL so intuitive! The API responses mirror the API requests.
Reading the Docs
Towards the right of the GraphiQL explorer, there’s a < Docs
button. Toggle it! (This is not to be confused with the topbar menu Docs
dropdown.) The < Docs
will toggle a little interface which tells us what to expect in our queries, and helps us when we use incorrect syntax. It will let us search by type.
Your first question, though, might be, how will we know the type of our data? In GraphQL, we can use __typename
on any data to get its type. For instance, we can edit the query we just wrote:
query {
viewer {
__typename
}
}
and we’ll see that viewer
has the type "User"
. If we now search the docs for "User"
, we’ll see there are many "Fields"
on user which we can explore. Try adding a few fields to your initial query.
User
Well, there must also be other "User"
s we can access instead of just ourselves. Let’s try it! Replace viewer
in the query from above with user
. When we run this snippet, we’ll see an error:
query {
user {
name
login
createdAt
}
}
The error will appear on our right pane. The error message tells us our problem, "Field 'user' is missing required arguments: login"
Ah! We haven’t told GraphQL which user we’re interested in. As it suggests, let’s pass in a user’s login. Linus Torvalds created git, so he seems like an appropriate user to play with. His login is torvalds
:
query {
user(login: "torvalds") {
name
login
createdAt
}
}
Neat. On the right side of your screen you should see that he’s had a GitHub account since 2011.
Connections
When looking at the User
docs, you might have noticed a type suffixed with "Connection"
, for instance, followers
has type "FollowerConnection"
.
In GraphQL, User
is a Node
. Nodes have edges, and lists of these edges are called Connections
. A Connection
is a way to see all nodes that are connected to a certain node in a specific way. In our case, we’re looking for all followers
nodes which are connected to Linus Torvalds. (See this Apollo blog post for further reading about connections.)
If we try typing followers
in the query, GraphiQL will give us an indication of an error. Hovering, we can read the error message, saying that followers
must have a selection of subfields. This is where GraphiQL is incredibly helpful. Hit run (Ctrl-enter) after typing followers
, and GraphiQL will autocomplete what its asking for:
query {
user(login: "torvalds") {
name
login
createdAt
followers {
edges {
node {
id
}
}
}
}
}
GraphiQL has auto-filled in the edges
, node
and id
field on followers
as defaults to give us some data about Linus’ followers. This makes sense given what we know about edges and nodes: followers has edges
and each of these is a node
.
But, if we look to the right side of our screen, we’ll see we have an error instead of results. The type "MISSING_PAGINATION_BOUNDARIES"
and message "You must provide a 'first' or 'last' value to properly paginate the 'followers' connection."
are both helpful here.
One of GraphQL’s real features is that it never returns more data than you ask it for. That said, we must tell it exactly how much data we want, by using (as prompted), the first
or last
field to limit the number of followers we’re asking for. Let’s look at Linus’ last 5 followers:
query {
user(login: "torvalds") {
name
login
createdAt
followers(last: 5) {
edges {
node {
id
}
}
}
}
}
This worked! But the id
s aren’t particularly informative. We can see the type of followers
by again using __typename
. Or, we can use Ctrl-space to autoprompt some fields we might be interested in. Instead of the id
field on a node
, let’s look at name
:
query {
user(login: "torvalds") {
name
login
createdAt
followers(last: 5) {
edges {
node {
name
}
}
}
}
}
Aha, we can see the name of a few of Linus’ followers. But, exactly how popular is he? For that, we can use the totalCount
field under followers
:
query {
user(login: "torvalds") {
name
login
createdAt
followers(last: 5) {
totalCount
}
}
}
As of the writing of this post, he has 124,812 followers. Notably, totalCount
was not limited by our pagination. This is because it is only returning a single value, not a series of values.
Query Variables
Reading this, you might have been curious how many followers a different user has. For that, we could replace "torvalds"
with a different user’s login. Or, we could learn about Query Variables!
This is the last remaining pane (on the bottom left) which we haven’t touched yet.
We first need to declare the argument within our query. GraphQL requires a type here. We’ll need to declare it in two places. The first is passing it into the query itself. The syntax is query ($variable_name:type!) { ...
In our case, we want to pass a login
of type String
, so query ($login:String!) {...
. Secondly, we want this to be our user’s login. So we can replace torvalds
with $login
as follows:
query ($login:String!) {
user(login: $login) {
name
followers(last: 5) {
totalCount
}
}
}
If we run this, our error message tells us that "Variable $login of type String! was provided invalid value"
! Ah! We still didn’t use our bottom left “Query Variables” pane. Let’s fill it in. Again, we can use the Ctrl-space to help us out: {"login": "jemmaissroff"}
. If we now hit run, we’ll see (among other things) that I have significantly fewer followers than Linus Torvalds.
TL;DR
For those short on time or attention:
- GraphQL query results mirror JSON, making them easy to parse, write and reason about
- GraphiQL is a helpful GraphQL IDE
__typename
gives the type of an item, helpful for reading the docs- Some queries have required arguments to limit the scope of a search, like
login
for user - Pagination is a feature of GraphQL, requiring us to limit our queries, sometimes using
first
orlast
- Query variables must have a type and be named in the query declaration
- Query variables then can be used throughout the query itself by referencing the name in the declaration
For an example of a queries which uses a few additional features of GraphQL, check out the queries I wrote here for a Ruby gem to find GitHub users’ emails.