An Introduction to GraphQL Queries

Queries in GraphQL are analogous to REST’s GET and they allow to ask the server for the data we need. Contrary to REST however, we get full power to ask for exactly what we need and in the shape we need it.

For this post we’ll run queries against a Star Wars public GraphQL API endpoint. See this Github repo for a list of public GraphQL endpoints that can be really useful to practice your GraphQL querying skills. You’ll notice that endpoints come with a tool called GraphiQL that makes it very easy to run queries. GraphiQL offers autocompletion and very useful error messages (thanks to the fact that GraphQL is a typed query language.)

A Basic Query

We can query for simple scalar types (Int, Float, String, Boolean or ID), which act as primitives, or we can query for objects. Notice how, when querying for objects, we need to start a new selection set:

{
  allFilms {
    films {
      title
    }
  }
}

Our films field is an object of type Film so we open a new selection set and in it we get the title field which is of type String

And here’s the data we get back:

{
  "data": {
    "allFilms": {
      "films": [
        {
          "title": "A New Hope"
        },
        {
          "title": "The Empire Strikes Back"
        },
        {
          "title": "Return of the Jedi"
        },
        ...

Named Queries

In the previous example, our query is anonymous. Much like with anonymous vs named functions in JavaScript, it’s often very useful to name our queries to later help with logging and debugging. Here’s the same query as above, this time with a name:

query GetTitles {
  allFilms {
    films {
      title
    }
  }
}

Comments

You can add comments in queries with the # character:

query GetTitles {
  allFilms {
    films {
      # Getting film titles
      title
    }
  }
}

Arguments

In many cases, you’ll need to pass arguments to indicate which entry to get:

query GetReturnOfTheJedi {
  film(id: "ZmlsbXM6Mw==") {
    title
    director
    releaseDate
  }
}

The response:

{
  "data": {
    "film": {
      "title": "Return of the Jedi",
      "director": "Richard Marquand",
      "releaseDate": "1983-05-25"
    }
  }
}

Variables

Instead of providing literal values directly as arguments, we can use variables. To do this, we specify a variable name prepended by $ with the query name along with the variable type, and then on the field itself we pass the variable name instead of the literal value:

query GetReturnOfTheJedi($id: ID) {
  film(id: $id) {
    title
    director
    releaseDate
  }
}

We would pass-in the variable value like this, where filmId is a variable in our program that contains the id to lookup:

{ "id": filmId }

Aliases

Sometimes a field name on the server doesn’t match the shape we want for the returned data. You can easily fix that with aliases:

query GetTitles {
  allFilms {
    films {
      filmTitle: title
    }
  }
}

And the returned data will look like this:

{
  "data": {
    "allFilms": {
      "films": [
        {
          "filmTitle": "A New Hope"
        },
        {
          "filmTitle": "The Empire Strikes Back"
        },
        {
          "filmTitle": "Return of the Jedi"
        },
        ...

Directives

There are two directives that come built-in with the GraphQL spec: @skip and @include, and they allow to filter returned data.

Let’s say that we’re starting with this passed-in as a query variable:

{"includeDirector" : true  }

@skip

Use @skip to omit data if a passed-in value is true:

query GetTitles($includeDirector: Boolean!) {
  allFilms {
    films {
      filmTitle: title
      director @skip(if: $includeDirector)
    }
  }
}

The response:

{
  "data": {
    "allFilms": {
      "films": [
        {
          "filmTitle": "A New Hope"
        },
        {
          "filmTitle": "The Empire Strikes Back"
        },
        {
          "filmTitle": "Return of the Jedi"
        },
        ...

Notice the ! after the Boolean type. This is used to indicate that the variable is required.

@include

Use @include for the opposite, to include data only if a passed-in value returns true:

query GetTitles($includeDirector: Boolean!) {
  allFilms {
    films {
      filmTitle: title
      director @include(if: $includeDirector)
    }
  }
}

The response:

{
  "data": {
    "allFilms": {
      "films": [
        {
          "filmTitle": "A New Hope",
          "director": "George Lucas"
        },
        {
          "filmTitle": "The Empire Strikes Back",
          "director": "Irvin Kershner"
        },
        {
          "filmTitle": "Return of the Jedi",
          "director": "Richard Marquand"
        },
        ...

Fragments

Many times, query fields would be repeated unnecessarily, like in this example:

query GetFilmInfo {
  film1: film(id: "ZmlsbXM6NA==") {
    title
    director
    producers
  }
  film2: film(id: "ZmlsbXM6Ng==") {
    title
    director
    producers
  }
}

In these cases, fragments come to the rescue:

query GetFilmInfo {
  film1: film(id: "ZmlsbXM6NA==") {
    ...info
  }
  film2: film(id: "ZmlsbXM6Ng==") {
    ...info
  }
}

fragment info on Film {
  title
  director
  producers
}

Notice how we spread our info fragment into our query to get the same result. Notice also how the fragment itself needs to be defined on a specific type. This allows for correct type checking across the board.

Inline Fragments

Inline fragments are a type of fragment defined as part of your queries. They become especially useful to deal with data that returns either an interface or an union type. They allow to deal with data differently depending on its type.

For this last example, let’s use an hypothetical example where a field entry can by of either type Post or Page:

query GetEntry($id: ID!) {
  entry(id: $id) {
    title
    ... on Post {
      keywords
      lastRevision
    }
    ... on Page {
      content
      publishedDate
    }
  }
}

If our returned entry is of type Post, we’ll get its title, keywords and lastRevision, and if it’s of type Page, we’ll get the title, content and published date.

Learning More

Refer to the official GraphQL documentation to dive deeper.

✖ Clear

🕵 Search Results

🔎 Searching...