Using GraphQL

Over the last few chapters, we've explored how to build React applications that interact with servers using JSON and HTTP APIs. In this chapter, we're going to explore GraphQL, which is a specific API protocol developed by Facebook that is a natural fit in the React ecosystem.

What is GraphQL? Most literally it means "Graph Query Language", which may sound familiar if you've worked with other query languages like SQL. If your server "speaks" GraphQL, then you can send it a GraphQL query string and expect a GraphQL response. We'll dive into the particulars soon, but the features of GraphQL make it particularly well-suited for cross-platform applications and large product teams.

To discover why, let's start with a little show-and-tell.

Your First GraphQL Query

Typically GraphQL queries are sent using HTTP requests, similar to how we sent API requests in earlier chapters; however, there is usually just one URL endpoint per-server that handles all GraphQL requests.

GraphQLHub is a GraphQL service that we'll use throughout this chapter to learn about GraphQL. Its GraphQL endpoint is https://www.graphqlhub.com/graphql, and we issue GraphQL queries using an HTTP POST method. Fire up a terminal and issue this cURL command:


$ curl -H 'Content-Type:application/graphql' -XPOST https://www.graphqlhub.com/graphql?pretty=true -d '{ hn { topStories(limit: 2) { title url } } }'
{
  "data": {
    "hn": {
      "topStories": [
        {
          "title": "Bank of Japan Is an Estimated Top 10 Holder in 90% of the Nikkei 225",
          "url": "http://www.bloomberg.com/news/articles/2016-04-24/the-tokyo-whale-is-quietly-buying-up-huge-stakes-in-japan-inc"
        },
        {
          "title": "Dropbox as a Git Server",
          "url": "http://www.anishathalye.com/2016/04/25/dropbox-as-a-true-git-server/"
        }
      ]
    }
  }
}

It may take a second to return, but you should see a JSON object describing the title and url of the top stories on Hacker News. Congratulations, you've just executed your first GraphQL query!

Let's break down what happened in that cURL. We first set the Content-Type header to application/graphql - this is how the GraphQLHub server knows that we're sending a GraphQL request, which is a common pattern for many GraphQL servers (we'll see later on in "Writing Your GraphQL Server").

Next we specified a POST to the /graphql?pretty=true endpoint. The /graphql portion is the path, and the pretty query parameters instructs the server to return the data in a human-friendly, indented format (instead of returning the JSON in one line of text).

Finally, the -d argument to our cURL command is how we specify the body of the POST request. For GraphQL requests, the body is often a GraphQL query. We had to write our request in one line for cURL, but here's what our query looks like when we expand and indent it properly:


// one line
{ hn { topStories(limit: 2) { title url } } }

// expanded
{
  hn {
    topStories(limit: 2) {
      title
      url
    }
  }
}

This is a GraphQL query. On the surface it may look similar to JSON, and they do have a tree structure and nested brackets in common, but there are crucial differences in syntax and function.

Notice that the structure of our query is the same structure returned in the JSON response. We specified some properties named hn, topStories, title, and url, and the response object has that exact tree structure - there are no extra or missing entries. This is one of the key features of GraphQL: you request the specific data you want from the server, and no other data is returned implicitly.

It isn't obvious from this example, but GraphQL not only tracks the properties available to query, but the type of each property as well ("type" as in number, string, boolean, etc). This GraphQL server knows that topStories will be a list of objects consisting of title and url entries, and that title and url are strings. The type system is much more powerful than just strings and objects, and really saves time in the long-run as a product grows more complex.

GraphQL Benefits

Now that we've seen a bit of GraphQL in action, you may be wondering, "why anyone would prefer GraphQL over URL-centric APIs such as REST?" At first glance, it seems like strictly more work and setup than traditional protocols - what do we get for the extra effort?

First, our API calls become easier to understand by declaring the exact data we want from the server. For a newcomer to a web app codebase, seeing GraphQL queries makes it immediately obvious what data is coming from the server versus what data is derived on the clients.

GraphQL also opens doors for better unit and integration testing: it's easy to mock data on the client, and it's possible to assert that your server GraphQL changes don't break GraphQL queries in client code.

GraphQL is also designed with performance in mind, especially with respect to mobile clients. Specifying only the data needed in each query prevents over-fetching (i.e., where the server retrieves and transmits data that ultimately goes unused by the client). This reduces network traffic and helps to improve speed on size-sensitive mobile environments.

The development experience for traditional JSON APIs is often acceptable at best (and infuriating more often). Most APIs are lacking in documentation, or worse have documentation that is inconsistent with the behavior of the API. APIs can change and it's not immediately obvious (i.e. with compile-time checks) what parts of your application will break. Very few APIs allow for discovery of properties or new endpoints, and usually it occurs in a bespoke mechanism.

GraphQL dramatically improves the developer experience - its type system provides a living form of self-documentation, and tooling like GraphiQL (which we play with in this chapter) allow for natural exploration of a GraphQL server.


Navigating a Schema with GraphiQL

Finally, the declarative nature of GraphQL pairs nicely with the declarative nature of React. A few projects, including the Relay framework from Facebook, are trying to bring the idea of "colocated queries" in React to life. Imagine writing a React component that automatically fetches the data it needs from the server, with no glue code around issuing API calls or tracking the lifecycle of a request.

All of these benefits compound as your team and product grow, which is why it evolved to be the primary way data is exchanged between client and server at Facebook.

GraphQL vs. REST

We've mentioned alternative protocols a bit, but let's compare GraphQL to REST specifically.

One drawback to REST is "endpoint creep." Imagine you're building a social network app and start with a /user/:id/profile endpoint. At first the data this endpoint returns is the same for every platform and every part of the app, but slowly your product evolves and accumulates more features that fit under the "profile" umbrella. This is problematic for new parts of the app that only need some profile data, such as tooltips on a news feed. So you might end up creating something like /user/:id/profile_short, which is a restricted version of the full profile.

As you run into more cases where new endpoints are required (imagine a profile_medium!), you now duplicate some data with calls to /profile and /profile_short, possibly wasting server and network resources. It also makes the development experience harder to understand - where does a developer find out what data is returned in each variation? Are your docs up-to-date?

An alternative to creating N endpoints is to add some GraphQL-esque functionality to query parameters, such as /user/:id/profile?include=user.name,user.id. This allows clients to specify the data they want, but still lacks many of the features of GraphQL that make such a system work in the long-run. For example, that sort of API there is still no strong typing information that enables resilient unit testing and long-lived code. This is especially critical for mobile apps, where old binaries might exist in the wild for long periods of time.

Lastly the tooling for developing against and debugging REST APIs is often lack-luster because there are so few commonalities among popular APIs. At the lowest level you have very general purpose tools like cURL and wget, some APIs might support Swagger or other documentation formats, and at the highest level for specific APIs like Elasticsearch or Facebook's Graph API you may find bespoke utilities. GraphQL's type system supports introspection (in other words, you can use GraphQL itself to discover information about a GraphQL server), which enables pluggable and portable developer tools.

GraphQL vs. SQL

It's also worthwhile to compare GraphQL to SQL (in the abstract, not tied to a specific database or implementation). There's some precedent for using SQL for web apps with the Facebook Query Language (FQL) - what makes GraphQL a better choice?

SQL is very helpful for accessing relational databases and works well with the way such databases are structured internally, but it is not how front-end applications are oriented to consume data. Dealing with concepts like joins and aggregations at the browser level feels like an abstraction leak - instead, we usually do want to think of information as a graph. We often think, "Get me this particular user, and then get me the friends of that user," where "friends" could be any type of connection, like photos or financial data.

There's also a security concern - it's awfully tempting to shove SQL from the web apps straight into the underlying databases, which will inevitably lead to security issues. And as we'll see later on, GraphQL also enables precise access control logic around who can see what kinds of data, and is generally more flexible and less likely to be as insecure as using raw SQL.

Remember that using GraphQL does not mean you have to abandon your backend SQL databases - GraphQL servers can sit on top of any data source, whether it's SQL, MongoDB, Redis, or even a third-party API. In fact, one of the benefits of GraphQL is that it is possible to write a single GraphQL sever that serves as an abstraction over several data stores (or other APIs) simultaneously.

Relay and GraphQL Frameworks

We've talked a lot about why you should consider GraphQL, but haven't gone much into how you use GraphQL. We'll start to uncover more about that very soon, but we should mention Relay.

Relay is Facebook's framework for connecting React components to a GraphQL server. It allows you to write code like this, which shows how an Item component can automatically retrieve data from a Hacker News GraphQL server:


class Item extends React.Component {
  render() {
    let item = this.props.item;

    return (
      <div>
        <h1><a href={item.url}>{item.title}</a></h1>
        <h2>{item.score} - {item.by.id}</h2>
        <hr />
      </div>
    );
  }
};

Item = Relay.createContainer(Item, {
  fragments: {
    item: () => Relay.QL`
      fragment on HackerNewsItem {
        id
        title,
        score,
        url
        by {
          id
        }
      }
    `
  },
});

Behind the scenes, Relay handles intelligently batching and caching data for improved performance and a consistent user experience. We'll go in-depth on Relay later on, but this should give you an idea of how nicely GraphQL and React can work together.

There are other emerging approaches on how to integrate GraphQL and React, such as Apollo by the Meteor team.

You can also use GraphQL without using React - it's easy to use GraphQL anywhere you'd traditionally use API calls, including with other technologies like Angular or Backbone.

Chapter Preview

There are two sides to using GraphQL: as an author of a client or front-end web application, and as an author of a GraphQL server. We're going to cover both of these aspects in this chapter and the next.

As a GraphQL client, consuming GraphQL is as easy as an HTTP request. We'll cover the syntax and features of the GraphQL language, as well as design patterns for integrating GraphQL into your JavaScript applications. This is what we'll cover in this chapter.

As a GraphQL server, using GraphQL is a powerful way to provide a query layer over any data source in your infrastructure (or even third-party APIs). GraphQL is just a standard for a query language, which means you can implement a GraphQL server in any language you like (such as Java, Ruby, or C). We're going to use Node for our GraphQL server implementation. We'll cover writing GraphQL servers in the next chapter.

Consuming GraphQL

If you're retrieving data from a server using GraphQL - whether it's with React, another JavaScript library, or a native iOS app - we think of that as a GraphQL "client." This means you'll be writing GraphQL queries and sending them up to the server.

Since GraphQL is its own language, we'll spend this chapter getting you familiar with it and learning to write idiomatic GraphQL. We'll also cover some mechanics of querying GraphQL servers, including various libraries and starting off with an in-browser IDE: GraphiQL.

Exploring With GraphiQL

At the start of the chapter we used GraphQLHub with cURL to execute a GraphQL query. This isn't the only way GraphQLHub provides access to its GraphQL endpoint: it also hosts a visual IDE called GraphiQL. GraphiQL is developed by Facebook and can be used hosted on any GraphQL server with minimal configuration.

You can always issue GraphQL requests using tools like cURL or any language that supports HTTP requests, but GraphiQL is particularly helpful while you become familiar with a particular GraphQL server or GraphQL in general. It provides type-ahead support for errors or suggestions, searchable documentation (generated dynamically using the GraphQL introspection queries), and a JSON viewer that supports code folding and syntax highlighting.

Head to https://graphqlhub.com/playground and get your first look at GraphiQL:


Empty GraphiQL

Not much going on yet - go ahead and enter the GraphQL query we cURL'd from earlier:


GraphiQL query