Learning GraphQL: What you need to know to get started

Alfonso Millán
Mar 18, 2018 · 7 min read
GraphQL traverses your application data graph producing query result trees

What is it?

GraphQL is an API Query Language created by Facebook in 2012 (released publicly in 2015) to describe data models for client-server applications, allowing for better client application development between front-end and back-end teams. It is used to query application servers where the query structure looks like the data that it returns (wha? 😱). A GraphQL query returns only the data that the client asks for and nothing more.

The reason that the query and data look similar is because they are both trees (more on this later). GraphQL does not mandate a particular programming language or storage system for application servers that implement it but the following examples assume a basic understanding of JavaScript.

For this post, I will explain the basic grammar, syntax and static type system of the GraphQL Schema Definition Language (SDL). I will compare GraphQL queries to traditional REST queries to highlight how it can improve your product development experience, especially with difficult to work with REST APIs.

I will also set up a Node.js/Express.js back-end GraphQL server to demonstrate how useful GraphQL can be for API aggregation. However, this only skims the surface of what GraphQL is capable of!

REST vs GraphQL

Typically, RESTful API endpoints have the following structure whenever you want to GET, POST, PUT or DELETE a resource from the server:

~/v1/artists/{id}/albums
~/v1/artists/{id}/top-tracks
~/v1/artists/{id}/related-artists

For every resource that you would like to use in your application, you have to hit multiple API endpoints. Furthermore, over-fetching (more data returned that you care about) or under-fetching (not having enough data returned and having to hit another endpoint) can lead to performance problems for your application. The client also has no knowledge of how the data being fetched is structured. The API endpoints themselves do not provide any metadata about the resources. Changes or deprecations to a REST API also provide challenges that must be dealt with carefully.

In comparison, with GraphQL, there are three types of operations that can be modeled and performed.

  1. query: a read-only fetch
  2. mutation: a write, followed by a fetch
  3. subscription: when a client subscribes to an event, it initiates and holds a steady connection to the server. When the particular event occurs, the server pushes the relevant data back to the client. This is useful for realtime connections and updates between clients and the server.

The structure of these operations is as shown:

# This query operation might retrieve where an artist is
# performing next, as well as the venues' locations
query {
event(artist: "Kendrick Lamar") {
venue_names
coordinates
}
}
# If a document contains only one query operation, and the query
# defines no variables & contains no directives, the query may be
# represented in short‐hand, omitting the query keyword & name.
# For example,{
field
}
# This mutation operation might “like” a story and then
# retrieve the new number of likes:
mutation {
likeStory(storyID: 12345) {
story {
likeCount
}
}
}
# We want to query a specific user (requested via the id argument)
# and their profile picture of a specific size:
{
user(id: 4) {
id
name
profilePic(size: 100)
}
}
# Subscriptions are written using the same syntax
# as queries and mutations
subscription {
user(id: 9001) {
name
}
}

Queries, mutations, and subscriptions can take arguments to narrow down response results or provide additional information that might be needed when requesting a resource. In our first example, the selection set has the field event, which itself contains another selection set of the fields venue_names and coordinates. Additionally, the structure of the query implicitly tells the client what the data results will look like — this can be useful for how some GraphQL clients implement caching.

The great thing about GraphQL is that it is up to the client to decide what fields they care about and to include or exclude them as needed when requesting data from the server. The returned payload tends to generally be smaller in size than traditional REST APIs that display all the data of an endpoint by default. Depending on how the back-end schema is defined, one can severely mitigate under and over-fetching! 😎

Fields are conceptually functions which return values, and occasionally accept arguments which alter their behavior. These arguments often map directly to function arguments within a GraphQL server’s implementation.

With these operations, a GraphQL query can request multiple resources from only one API endpoint with a simple POST request:

// Sample GraphQL endpoint
// https://www.app-does-not-exist.com/graphql
// Sample POST request using fetch
// Note how the body field's structure matches a query operation
fetchData(artist) { return fetch('https://www.app-does-not-exist.com/graphql', {
method: 'POST',
body: JSON.stringify({ query: `{ event(artist: "${artist}") { venue_names coordinates} }` }), headers: { 'Content-Type': 'application/json' },
})
.then(res => res.json()) .catch(error => console.error(error));}

In order to compose GraphQL queries and mutations to reduce duplication, Fragments are employed similar to how “DRYing” up code can be achieved by extrapolating repeated sections of code into a function. A more in-depth look at the anatomy of a GraphQL query is presented here by the Apollo team.

What do the results look like?

The response from our GraphQL server will return a JSON object (note however that GraphQL does not require a specific serialization format) with a root node of “data” that branches out based on the requested fields. The keys will by default be the field names but this can be changed using an alias if desired.

Representation of the returned JSON; the returned data represents the “leaves” of the query

The scalar values can be of the following types*:

  • Int: A signed 32‐bit integer.
  • Float: A signed double-precision floating-point value.
  • String: A UTF‐8 character sequence.
  • Boolean: true or false.
  • ID: The ID scalar type represents a unique identifier, often used to refetch an object or as the key for a cache. The ID type is serialized in the same way as a String; however, defining it as an ID signifies that it is not intended to be human‐readable.
  • *Date: custom scalar data types can also be implemented.

So…about that back-end schema?

With the basics out of the way, we can now move on to implementing our own GraphQL server using Express. For this demo, I am going to be using the free and public Pokemon API because I:

  1. Don’t need OAuth or an API Key, it’s an open API
  2. Spent way too long trying to select an API for this demo
  3. Gotta catch ‘em all

However, the principles and setup would be the same for any RESTful API that returns JSON or XML — GraphQL can even serve as a wrapper to existing micro-services or legacy systems. It can aggregate data from multiple APIs simultaneously.

Initial Setup

First, using your terminal, create a new directory and set up an initial package.json:

> mkdir graphql-demo
> cd graphql-demo
> npm init -y

Now, go ahead and create two files that we will be using for the server and the schema:

> touch schema.js server.js

Install the necessary packages from npm (explained in the comments in the code):

> npm i graphql express express-graphql node-fetch dataloader cors --save

Simple Server & Schema

Below are the gists for schema.js and server.js but you can also clone the github repo I set up for this example to try it out for yourself!

After running “npm run start” on your terminal, you should be able to open http://localhost:3000/graphql and start querying based off varying id’s!

# Sample Query
{
Pokemon(id: 149){
id
name
}
}
# Sample response from /graphql endpoint
{
"data": {
"Pokemon": {
"id": 149,
"name": "dragonite"
}
}
}

This example showcases a small sample of what’s possible with GraphQL — If you are interested in learning more, GraphQL’s documentation is an excellent resource. Now that our /graphql endpoint is setup, we can query it in the front-end (using React, Angular, Vue, etc.) for the Pokemon we’d like to know more about and build custom UI components based on our results.

TL;DR

  • Very likely that GraphQL will start being used more in front-end and back-end development. It can replace or be used alongside of existing REST based APIs, especially those that are bad implementations of REST
  • GraphQL is language agnostic, there are implementations for many programming languages. Facebook’s reference implementation was in JavaScript
  • GraphQL links your application data graph to query result trees (trees are a subset of graphs — see the talk in the Additional Resources section for a better mental model)
  • Schema setup and query operations look familiar, resulting in self-documenting code
  • GraphQL can be used with all major front-end JavaScript frameworks
  • There are several existing GraphQL clients that can help streamline setting up a GraphQL server but a simple Express server is enough to get started; can also use various server libraries
  • Can replace Redux (Just kidding! But it can help simplify your store significantly)
  • REST based APIs excel at caching due to how they are architectured; with GraphQL caching isn’t as simple to implement/take advantage of but it is still possible
  • It is not a magic bullet or catch-all solution but another great tool for the toolbox

Additional Resources

Notice any mistakes or have any questions? Comment down below. Happy coding 😃

Alfonso Millán

Written by

Former mechanical engineer turned software developer. Living in NYC.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade