| <!-- -->Code Cartoons

A cartoon guide to Facebook's Relay, part 1: Saying what data you need with GraphQL

The last two cartoons covered Flux and Redux. Those are data handling patterns to keep your UI in sync. When a user interaction happens, they update the state and trigger rerendering.

But where's the cloud? How do you get the data that a component needs from a server, and then update the server when the user makes changes?

The Flux docs don't tell you were to put this. Even at Facebook, different teams add it in different parts of the app. Redux gives you a single place to do it (middleware), but it still requires effort to wire it up.

Where's the cloud? There's no set spot in Flux (left). Redux (right) uses middleware.

Relay takes care of this problem. It makes it easy to fetch data from the server as part of your data flow. In order to do this, Relay needs to know what data each component needs from the server. This is where GraphQL comes in.

So let's look at GraphQL. But first…

What is a graph?

You might think of a graph as the same thing as a chart, or the graphs you made on a graphing calculator. That's not the kind of graph we're talking about.

The kind of graph we're talking about is a group of things that are connected to each other by relationships. These things and relationships have special names in graph theory. The things are called nodes and the relationships between them are called edges.

If that sounds unfamiliar, just think of a property chain. For example, user.friend[0].attending[0]. That' another way of thinking about the same graph.

If you look at an app like Facebook, a graph is the most natural way to think about the data. There are lots of things, and lots of relationships between those things.

When you pull up a page on Facebook, it's showing you a particular view of that graph. And each component on the page shows you a small slice of the graph.

So how do you make the connection between a component and the small section of the graph that it displays?

This is what GraphQL does. It makes it possible to indicate the small section of the graph that you want. This small section is called a fragment. The fragments combine to create a larger query.

Relay piggybacks on this capability—being able to combine multiple fragments into a larger query — to solve a problem.

The problem

So what is the problem that Relay solves using GraphQL?

When you build React components, it's easy to reuse them across different parts of your site. This is one of the main benefits of React. It's called composability.

If your component needs to use data from the server, though, it gets harder to just drop a component in place. The server needs to know what properties the component needs. In many apps, this will be hard-coded on the server. There will be a URL (called an endpoint) that passes down data for that particular view. The endpoint code will know exactly what properties its view needs.

The problem here is that whenever you add (or remove) properties from the component, you have to change the server code too. This is called coupling; when you change one, you have to change the other, too.

Because you have to manually keep these two in sync, it makes bugs and obsolete code more likely.

  • Bugs come from underfetching data. You don't pull down the properties that you need for a component because you forgot to add them to the server.
  • Obsolete code results in overfetching data. For example, let's say you remove a component from the tree. Do you delete its properties from the server response? How can you be sure another component doesn't use that endpoint and need those properties? Instead, it's better to just keep them in the response… but then you have a lot of cruft lying around.

The solution: declarative data fetching

With GraphQL, you don't hard-code the server with the list of properties that your view needs. Instead, the component provides a list of what it needs to the server.

This list is combined with the lists from other components. The structure of the combined list is a tree, just like the component tree. It gets handed off to the endpoint. There's only one endpoint and it handles all requests.

The nice thing about this is that it localizes changes. When you need to add or remove a property, you only need to change the component… not the server.

What GraphQL looks like

To make this work, each component needs to provide the list of properties that it needs from the server. This is the query fragment. Relay will figure out which components are going to render and will get the query fragments for them. It will compile these into a single query — a consolidated list of properties that it needs from the server.

This turns into a query like this:

query {
    user(id: 5) {
      friends(first: 3) {
        picture
        name
        location
      }
    }
  }

This consolidated query is kind of like a questionnaire. The client has laid out all of the questions it wants the server to answer, and the server just needs to fill in the blanks.

One important thing to note: GraphQL doesn't actually store your data. It just gives you a language to ask for data.

If your database is the public library, then GraphQL would be the librarian. It just listens to your request and figures out what you want. Then it goes around to the different bookshelves and finds the data that you asked for. The bookshelves in this analogy are the tables of your database, or whatever you are holding your data in.

This means you can use GraphQL on top of all sorts of different backends; an existing MySQL database, a NoSQL database like MongoDB, or even on top of regular text files.

For each property in the query, the server will have a resolve() function. This is where GraphQL figures out the value and fills in that question on the questionnaire, computing a value or querying a database.

Coming up next…

There's more work to do than just splitting up the query. That's where Relay comes in. I'll cover that in part 2.