RESTful APIs vs GraphQL APIs by Example

Samer Buna
EdgeCoders
Published in
6 min readMar 11, 2016

--

Let’s imagine that we are the developers responsible for building a shiny new user interface to represent the Star Wars films and characters.

The first UI we’ve been tasked to build is simple: a view to show information about a single Star Wars person, for example, Darth Vader, and all the films this person appeared in. This view should display the person’s name, birth year, planet name, and the titles of all the films in which they appeared.

As simple as that sounds, we’re actually dealing with 3 different resources here: Person, Planet, and Film. The relation between these resources is simple and anyone can guess the shape of the data here. A person object belongs to one planet object, and it will have one or more films objects.

The JSON data for this UI could be something like:

{
"data": {
"person": {
"name": "Darth Vader",
"birthYear": "41.9BBY",
"planet": {
"name": "Tatooine"
},
"films": [
{ "title": "A New Hope" },
{ "title": "The Empire Strikes Back" },
{ "title": "Return of the Jedi" },
{ "title": "Revenge of the Sith" }
]
}
}
}

Assuming a data service gave us this exact structure for the data, here’s one possible way to represent its view with React.js:

// The Container Component:
<PersonProfile person={data.person} ></PersonProfile>
// The PersonProfile Component:
Name: {person.name}
Birth Year: {person.birthYear}
Planet: {person.planet.name}
Films: {person.films.map(film => film.title)}

This is a simple example, and while our experience with Star Wars might have helped us here a bit, the relationship between the UI and the data is very clear. The UI used all the “keys” from the JSON data object we imagined.

Let’s now see how we can ask for this data using a RESTful API.

We need a single person’s information, and assuming that we know the ID of that person, a RESTful API is expected to expose that information as:

GET - /people/{id}

This request will give us the name, birthYear, and other information about the person. A good RESTful API will also give us the ID of this person’s planet, and an array of IDs for all the films this person appeared in.

The JSON response for this request could be something like:

{
"name": "Darth Vader",
"birthYear": "41.9BBY",
"planetId": 1
"filmIds": [1, 2, 3, 6],
*** other information we do not need ***
}

Then to read the planet’s name, we ask:

GET - /planets/1

And to read the films titles, we ask:

GET - /films/1
GET - /films/2
GET - /films/3
GET - /films/6

Once we have all 6 responses from the server, we can combine them to satisfy the data needed by our view.

Besides the fact that we had to do 6 round trips to satisfy a simple data need for a simple UI, our approach here was imperative. We gave instructions for how to fetch the data and how to process it to make it ready for the view.

Star Wars data has a RESTful API currently hosted at http://swapi.co/. Go ahead and try to construct our data person object there; the keys might be a bit different, but the API endpoints will be the same. You will need to do exactly 6 API calls. Furthermore, you will have to over-fetch information that the view does not need.

Of course, this is just one implementation of a RESTful API for this data. There could be better implementations that will make this view easier to implement. For example, if the API server implemented nested resources and understood the relation between a person and a film, we could read the films data with:

GET - /people/{id}/films

However, most likely, a pure RESTful API server would not implement that, and we would need to ask our backend engineers to create this custom endpoint for us. That’s the reality of scaling a RESTful API, we just add custom endpoints to efficiently satisfy the growing clients needs. Managing custom endpoints like these is hard.

Let’s now look at the GraphQL approach. GraphQL on the server embraces the custom endpoints idea and takes it to its extreme. The server will be just a single endpoint, and the channel does not matter. If we’re doing this over HTTP, the HTTP method certainly wouldn’t matter either. Let’s assume we have a single GraphQL endpoint exposed over HTTP at /graphql

Since we want to ask for the data we need in a single round-trip, we’ll need a way to express our complete data needs for the server. We do this with a GraphQL query:

GET or POST - /graphql?query={...}

A GraphQL query is just a string, but it will have to include all the pieces of the data that we need, and this is where the declarative power comes in.

In English, here’s how we declare our data requirement: we need a person’s name, birth year, their planet’s name, and the titles of all their films. In GraphQL, this translates to:

{
person(ID: ...) {
name,
birthYear,
planet {
name
},
films {
title
}
}
}

Read the English-expressed requirements one more time and compare it to the GraphQL query. It’s as close as it can get. Now compare this GraphQL query with the original JSON data that we started with. The GraphQL query is the exact structure of the JSON data, except without all the “values” parts. If we think of this in terms of a question-answer relation, the question is the answer statement without the answer part.

If the answer statement is:

The closest planet to the Sun is Mercury.

A good representation of the question is the same statement without the answer part:

(What is) the closest planet to the Sun?

The same relation applies to a GraphQL query. Take a JSON response, remove all the “answer” parts (which are the values), and you end up with a GraphQL query very suitable to represent a question about that JSON response.

Now compare the GraphQL query with the declarative React UI we defined for the data. Everything in the GraphQL query is used in the UI, and everything used in the UI appears in the GraphQL query. This is the great mental model of GraphQL. The UI knows the exact data it needs, and extracting that requirement is fairly easy. Coming up with a GraphQL query is simply the task of extracting what’s used as variables directly from the UI. If we invert this model, it would still hold the power. If we have a GraphQL query, we know exactly how to use its response in the UI, because the query will be the same “structure” as the response. We don’t need to inspect the response to know how to use it, and we don’t need any documentation about the API; it’s all built-in.

Star Wars data has a GraphQL API hosted at https://github.com/graphql/swapi-graphql. Go ahead and try to construct our data person object there. There are a few minor differences that we’ll explain later, but here’s the official query you can use against this API to read our data requirement for the view (with Darth Vader as an example):

{
person(personID: 4) {
name,
birthYear,
homeworld {
name
},
filmConnection {
films {
title
}
}
}
}

This request gives us a response structure very close to what our view used, and remember, we’re getting all of this data in a single round-trip.

If you’re interested to learn more about GraphQL (and Relay), I wrote a book about them.

Samer Buna is the organizer of ReactjsCamp.com, and he is the author of “React.js: Getting Started”, “Building Data-driven React Applications with Relay, GraphQL, and Flux” and multiple other courses on Pluralsight.

--

--

Samer Buna
EdgeCoders

Author for Pluralsight, O'Reilly, Manning, and LinkedIn Learning. Curator of jsComplete.com