GraphQL Query Basics

Learn the basics of writing queries using GraphQL

GraphQL is often touted for its efficiency when consuming data from APIs. There are two key aspects to its efficiency:

  • You get only the data you need: GraphQL will only respond with the fields you specify. This means it doesn't need to send unnecessary data across the wire, potentially saving your application – and your users – significant amounts of data over the course of numerous transactions.
  • You get all the data you need in a single request: Rather than spread different parts of the data across multiple endpoints, GraphQL lets you get all the data you require via a single request. For example, you can get user information and their order information in a single query, rather than sending requests to two separate endpoints.

Both of these benefits are made possible by the way GraphQL lets you construct a query. Let's look at some of the basics of constructing a query in GraphQL to retrieve data:

Get Set up to Create Queries

The GitHub GraphQL API is a large and complex GraphQL API that offers a way to explore many of GraphQL's query features.

There are two ways to explore the API:

This tutorial uses GraphQL Playground.

Follow the steps below set up and use the API:

  1. Add the API endpoint: https://api.github.com/graphql for GraphQL Playground. At this point you'll get a 401 error if you try to run anything. You'll fix that in the next step.
  2. Add an Authorization header to the HTTP headers (located at the bottom left of the application window):
{
  "Authorization":"Bearer MY_TOKEN"
}

HTTP Headers in Playground

  1. Click the Docs tab on the far right to explore the types and queries available within the GitHub API.

Playground Schema docs

Now you're ready to start building a query.

Create your First Query

Start with a relatively simple topic query, to find out how many people are following a "GraphQL" topic on GitHub.

With a RESTful API, this might involve calling an endpoint such as /v3/search/topics that returns all of the necessary details. However, every GraphQL query calls the same endpoint, so you must define what you are querying in the request. Luckily, GraphQL IDEs like GraphiQL or the GraphQL Playground offer code hinting.

Start by calling the topic query:

{
  topic
}

You may notice that your GraphQL IDE indicates that there is an error in your request.

GraphQL query error

The error indicates the topic query expects a name argument of type string. So, add your first argument in parentheses after the query:

{
  topic(name: "graphql")
}

Even with this change, an error still occurs. Why? GraphQL requires you to specify the fields required within your query, in order to supply you with only the data you need. There is no equivalent of select * in GraphQL, and this is for a number of good reasons. So, let's specify some fields within the query.

The topic query has six fields available, but you're only interested in the number of people following it, or the stargazersCount field, so modify the query to look as follows:

{
  topic(name: "graphql") {
    stargazerCount
  }
}

Finally, no errors. Run our query. The response should look similar to the following:

{
  "data": {
    "topic": {
      "stargazerCount": 12201
    }
  }
}

Notice that the response matches the query, meaning you don't need to waste time figuring out the structure of the response.

Arguments

The above example uses a single string argument. In addition to any of the GraphQL basic types, an argument can also be an enum or even a custom object type. For example, GitHub's search query takes a searchType enum argument that can be set to ISSUE,REPOSITORY or USER:

{
  search(query: "GraphQL", type: REPOSITORY) {
    repositoryCount
  }
}

The example below shows a custom object called repositories within a user query. It takes a custom object argument of type RespositoryOrder that specifies both the field to order by and the direction in which to order:

...
repositories(orderBy: {field:UPDATED_AT, direction: DESC}) {
...

Note: This snippet is from a larger query that will be explored in more detail further down.

The point here is that GraphQL enables APIs to support very complex querying capabilities in arguments.

Nested Objects

So far, you have a very simple query that gets a single field. Let's make this a little bit more complex by adding a nested object to get multiple sets of data in a single query. In this case, you will use the relatedTopics object to get a list of topics related to "GraphQL" within GitHub:

{
  topic(name:"graphql") {
    stargazerCount
    relatedTopics {
      name
      stargazerCount
    }
  }
}

You must specify the object and the fields within that object that you want to retrieve. In this case, relatedTopics did not require an argument. However, if you look at the docs, you'll see that it does have an optional argument (first) that defaults to 3, meaning it will only send the first three results. Let's define that to return 10 (the maximum the API allows):

{
  topic(name:"graphql") {
    stargazerCount
    relatedTopics(first: 10) {
      name
      stargazerCount
    }
  }
}

This shows that you can specify arguments both on the primary query and on nested object queries, as defined by the schema.

Aliases

Now imagine that you want to get the stargazer count for both GraphQL and JavaScript in a single request. You might try something like this:

{
  topic(name: "graphql") {
    stargazerCount
  }
  topic(name: "javascript") {
    stargazerCount
  }
}

That results in an error because you defined conflicting queries in a single request. To solve this, use an alias on each of the queries:

{
  graphql:topic(name: "graphql") {
    stargazerCount
  }
  javascript:topic(name: "javascript") {
    stargazerCount
  }
}

This returns a response containing the aliases you specified:

{
  "data": {
    "graphql": {
      "stargazerCount": 12203
    },
    "javascript": {
      "stargazerCount": 73700
    }
  }
}

It's worth noting that the alias can be any string you want, though it cannot start with a number or contain any special characters other than an underscore (though it can start with an underscore).

Fragments

Let's modify this query to get more than just the stargazerCount. To avoid writing code for each aliased query, you can use fragments which represent reusable pieces of query code. For example, instead of writing this:

{
  graphql:topic(name:"graphql") {
    stargazerCount
    relatedTopics(first: 10) {
      name
      stargazerCount
    }
  }
  javascript:topic(name:"javascript") {
    stargazerCount
    relatedTopics(first: 10) {
      name
      stargazerCount
    }
  }
}

You can encapsulate the reusable code in a fragment like this:

{
  graphql:topic(name:"graphql") {
    ...topicDetails
  }
  javascript:topic(name:"javascript") {
    ...topicDetails
  }
}

fragment topicDetails on Topic {
	stargazerCount
    relatedTopics(first: 10) {
      name
      stargazerCount
    }
}

You define the fragment by specifying fragment followed by a name (topicDetails in this case) and its type (Topic in this case) for validation purposes.

Then, you can reuse the fragment by referencing its name, prefixed by three dots (...topicDetails in this case) wherever you need to reuse it. While this example doesn't save a lot of code, it can be particularly useful when you find yourself repeating large chunks of code in a complex query.

Variables

Imagine you want to create a query that gets the user profile information and recent repositories for a user. This wouldn't work if you had to pass a hard-coded user string. Instead, GraphQL enables you to define a variable and then pass in a variables object to the query to populate the variables.

First, let's look at the query. This query basically gives you everything you might want to know to construct a profile page for a GitHub user (perhaps for a developer portfolio home page or something):

query GitHubUserProfile($username: String!)  {
  user(login:$username) {
    name
    company
    bio
    twitterUsername
    websiteUrl
    url
    repositories(first: 10, privacy: PUBLIC, orderBy: {field:UPDATED_AT, direction: DESC}) {
      totalCount
      edges {
        node {
          name
          description
          url
        }
      }
    }
  }
}

Up until now, you have been using an anonymous operation (i.e., wrapping the query in curly braces). Best practice says you should define the operation type and name. In this case, the operation type is a query and the name is GitHubUserProfile. There are other operation types such as a mutation (modifies data on the server) and a subscription (subscribes to updates to changes from the server).

You defined a variable $username (all variables must be prefixed by a $) of type String. The exclamation point (!) indicates that this variable is a required argument. Within the user query, you now reference the $username variable as the value for the login argument.

To specify that argument, you must pass in a JSON object containing a value for username. You can do that in GraphQL Playground via the Variables tab at the bottom left of the application:

GraphQL variables

Supply a GitHub username:

{
  "username": "remotesynth"
}

You can see the result of running the query on the right.

For More Information

Visit the following resources for more information:

This site uses cookies: By using this website, you consent to our use of cookies in accordance with our Website Terms of Use and Cookie Policy.