{ The Rithm Blog. }

An Introduction to GraphQL - Queries October 15, 2019

Welcome! If you're reading this, you have probably been told that GraphQL is one of, if not the best thing since the internet. Or maybe you've just been working with REST for so long that you think there's a better way. Regardless of where you're coming from, we'll be introducing what GraphQL is, how it acts as an alternative to REST, and how to get started with queries.

So what is it?

Before we dive too deep into the technicalities, let's just explain what GraphQL is. Unlike a framework or library, GraphQL is not programming language specific. GraphQL isn't tied to any specific database or storage engine and is instead backed by your existing code and data.

Instead, it is a query language for your API. It provides an alternative to REST and allows you to only have a single endpoint for your queries.

If you're familiar with building APIs, you know that it's very common to have an API endpoint for each action you take on a resource. For example, if we look at the GitHub API, we'll see the following endpoints:

  • GET /users/:username
  • GET /search/users
  • POST /user/repos

This structure is based on the idea of RESTful routing and having HTTP verbs correspond to actions around resources.

Each of these endpoints can be accessed with an HTTP request, either using AJAX or with a server side request.

As the GitHub documentation states, "The REST API v3 has numerous endpoints; the GraphQL API v4 has a single endpoint" - /graphql

Every single resource like users and repositories can be accessed using this single endpoint!

What makes this so powerful is that a single endpoint gives clients the power to describe exactly what data they want. Instead of a fixed endpoint that is harder to request customized data, GraphQL allows for flexible queries, which is often times far more efficient.

How do you work with it?

With GraphQL, you can consume a GraphQL server (that's what we'll do) using a client or build your own GraphQL servers. In order to explain what we mean by that, let's define some essential GraphQL terms (from the Apollo documentation) :

  • Schema - A GraphQL schema is at the center of any GraphQL server implementation and describes the functionality available to the clients which connect to it.

  • Field - A unit of data you are asking for in a Schema, which ends up as a field in your JSON response data.

  • Query - A read-only fetch operation to request data from a GraphQL service.

  • Mutation - An operation for creating, modifying and destroying data.

  • Subscription - A real-time GraphQL operation. A Subscription is defined in a schema along with queries and mutations.

  • Resolver - Provides the instructions for turning a GraphQL operation into data. It can retrieve data from or write data to anywhere, including a SQL, No-SQL, or graph database, a micro-service, and a REST API.

Now that you have an idea of what the basic terms mean, let's see what you can do at a high level on the client and server side.

  • Client

    • Make HTTP requests to a GraphQL endpoint as a query, mutation or subscription
    • Store information in a client-side cache (common with more advanced implementations)
  • Server

    • Define schemas which specify types
    • Define queries and resolvers
    • Define mutations and subscriptions

Why would I use it?

For starters, the ability for a client to shape the request is unique and valuable.

Here are some other reasons:

  1. GraphQL only has one URL. It does not need a resource URL + verb combo. The request details are often in a POST body.

  2. In REST, the shape and size of the data resource is determined by the server, with GraphQL its determined by the query (request)

  3. In REST, you have to make multiple API calls to retrieve relational data, with GraphQL you can start with entry resource and traverse all the connections in one request

  4. GraphQL has built in strong typing, which prevents silly mistakes with requests.

Enough talking - show me some code!

The easiest place to get started with GraphQL is to work with an existing GraphQL server and use a client to make requests to it. You could use AJAX, make server side requests or use a web based tool to make these requests.

To get started, we're going to be using a tool called Graphcool and interact with the Star Wars API. You might have used their REST API at https://swapi.co/. Instead of the REST API, we'll be using their GraphQL API.

To do that, let's head over to https://swapi.graph.cool

Making our first request

Once we're here, let's make our first query by adding the following on the left hand side.

query {
  allFilms {
    title
  }
}

When we click the play button, we see:

{
  "data": {
    "allFilms": [
      {
        "title": "A New Hope"
      },
      {
        "title": "Attack of the Clones"
      },
      {
        "title": "The Phantom Menace"
      },
      {
        "title": "Revenge of the Sith"
      },
      {
        "title": "Return of the Jedi"
      },
      {
        "title": "The Empire Strikes Back"
      },
      {
        "title": "The Force Awakens"
      }
    ]
  }
}

So what did we just do here? https://swapi.graph.cool/ is a GraphQL endpoint where we can make queries. Queries are how we fetch data from an API with GraphQL. Inside of the query, we specify the name of the query and what fields we want.

Let's break this down a bit:

query {
  allFilms {
    title
  }
}

  • Make a query using the query keyword

  • Inside of {}, specify the name of the query - in our case allFilms. You can find the names of these queries in the documentation.

  • Inside of allFilms we pass in the fields we want per line.

Try this query and see what you get!

query {
  allFilms {
    title
    director
  }
}

Nested queries

So far we've queried all of the films, but the Star Wars API allows us to query for nested fields. Let's try this query in the playground:

query {
  allFilms {
    title
    director
    planets {
     name
    }
  }
}

What you should see is now the name of each of the planets for each of the films. If you just try to query for planets alone we will get an error, so when querying for sub-fields, always make sure you specify what part of the field you would like. Notice how convenient it is, that you only request the data you need - nothing more or less!

Querying with Arguments

With REST, you can only pass a single set of arguments - in the query string or URL. In GraphQL, every field and nested object can get its own set of arguments.

Arguments can be of many different types, in our case let's look at an example where the argument is a string:

query {
  Film (title:"A New Hope" ) {
    director
    characters {
      name
    }
  }
}

Giving our query a name

Up until now, we have been using a shorthand syntax where we omit both the query keyword and the query name, but in production apps it's useful to use these to make our code less ambiguous.

The operation name is a meaningful and explicit name for your operation. It is only required in multi-operation documents, but its use is encouraged because it is very helpful for debugging and server-side logging.

This means that we go from:

query {
  Film (title:"A New Hope" ) {
    director
    characters {
      name
    }
  }
}

To:

query findSingleFilm {
  Film(title:"A New Hope" ) {
    director
    characters {
      name
    }
  }
}

Querying with Variables

In the real world, you often will not know what values will go into your queries when you define them. Just like in any programming language, we can add variables as placeholders

When we start working with variables, we need to do three things:

  1. Replace any static value in the query with a $variableName. We declare variables using a $

  2. Pass a value for the variable name in an object.

  3. All declared variables must be either scalars, enums, or input object types. So if you want to pass a complex object into a field, you need to know what input type that matches on the server. You can learn more about input object types on the Schema page.

query getSingleFilm($title: String!){
  Film(title:$title) {
    director
    characters {
      name
    }
  }
}

# Query Variables 
{
  "title": "the empire strikes back"
}

GraphQL also allows us to query with default values, similar to default parameters in a function. Here's what that looks like:

query getStarship($starshipName: String="Millennium Falcon"){
  Starship(name: $starshipName){
    name
  }
}

Making API calls using fetch

Before we go, let's take the knowledge we have now from our Graphcool playground, and use some client-side JavaScript to fetch data!

Below, we'll make a simple AJAX request and console.log the response we get back, try this out in the Chrome console!

fetch('https://swapi.graph.cool', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ query: '{ allFilms { title } }' }),
})
  .then(res => res.json())
  .then(res => console.log(res.data.allFilms));

Next Steps

We've just started scratching the surface of GraphQL. In the next post, we'll discuss mutations, types and subscriptions and even more about queries. Until then, you can read all about queries here.

Written by Elie Elie

Back to all posts

Get Started with Rithm School