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 ids 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 or last
  • 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.