A guide to GraphQL for front-end developers

10 months ago, Artsy Engineering Lead, Alan Johnson proclaimed that ‘I have seen the future, and it looks a lot like GraphQL’.

Fast-forward to exactly 13 days before I started this article, and Wired Magazine publishes a story title How Facebook has changed computing, highlighting GraphQL as one of the technologies that ‘played a tremendous role in shifting not only in the way we build our servers but also how we write code’.

These are bold claims! I am by no means qualified to counter nor concur them. However, for me, the above is indicative of how astronomically fast the GraphQL eco-system has grown over the past two years – regardless of whether we think this is for better or for worse.

This growth is also reflected in my day-to-day experience as a developer. Internally at OpenUp, our team has been steadily adopting GraphQL in more and more of our products, due to it solving a lot of pain-points usually associated with the REST API endpoints. Furthermore, we are not alone. GraphQL is widely used by a range of international tech teams from PinterestTwitterYelpNew York TimesPaypalAtlassianFacebookGithub (amongst others); and fellow South African startups like GetTruckBettr and Dine4Six.

After reading the above Wired article I reflected on my own (sometimes turbulent) journey through GraphQL, and I thought that it might be of value to compile a (hopefully!) easy guide for other front-end developers interested in getting started (and avoiding common pitfalls) learning GraphQL.

I’ve broken the below into the following broad topics, so feel free to skip ahead if you are only interested in a specific aspect of GraphQL:

My own journey learning GraphQL

When I first heard about GraphQL I’ve been playing around with this thing called React for a while. I’ve used a bit of Backbone and AngularJSbefore, but neither really stuck with me.

However, I was extremely excited by React’s functional approach to state management and the usage of a Virtual DOM to reduce the performance footprint of intensive DOM manipulations. By this time I’ve essential hand-rolled my own HyperScript-esque helper function to do the above and was looking forward to getting rid of the latter abomination in favour of React.createClass() and React.createElement() .

Before giving the above a spin in a production environment I thought it wise to ask a senior team member what he thinks of this React thing. Yet, no good (or perhaps prudent) deed goes unpunished: I was berated with the usual disdain held by a lot of back-end developers at that point (and for some even still today) towards JavaScript frameworks. However (and perhaps as a gesture of goodwill), he did mention that this GraphQL thing (that the team behind React is working on) looks really promising.

Which lead me to the following:

  • Googling GraphQL.
  • Reading a couple of overviews.
  • Still having no idea what GraphQL is.
  • Assuming that it’s probably aimed at web developers with at least one (or multiple) computer science degrees (I guess the way I still feel about Web Assembly and Houdini)
  • Going on with my life.

A couple of years later, after being sucked in by the gravitational pull of the front-end supernova that has become the React ecosystem, I started playing around with another tool called Gatsby. I’ve been struggling to get React Helmet to play nice with my own Frankenstein React static site generator built on top of static-site-generator-webpack-plugin.

I actually found a message in the #react Slack channel on ZA Tech that nicely encapsulates the frustration I felt at that time:

September 14th, 2017

Schalk Venter 4:02 PM
I might be missing something obvious here 😥

Schalk Venter 4:38 PM
However, either I’m misunderstanding the documentation or server-side rendering is not as easy as they make it out in the docs. 🤔

So this Gatsby-thing seemed to give me what I was trying to hack together by other means. However, I was met with further frustration as I came to realise that Gatsby is in cahoots with my previous nemesis, GraphQL (as a means to query front-matter and textual content from Markdown files). However, going back to my Frankenstein-mess really didn’t seem to be compelling either.

Turns out I really didn’t have a choice but to learn GraphQL at this point.

This meant that I needed to find answers to the following:

So what exactly is GraphQL?

“I have seen the future, and it looks a lot like GraphQL. Mark my words: in 5 years, newly minted full-stack app developers won’t be debating RESTfulness anymore, because REST API design will be obsolete. […] It lets you model the resources and processes provided by a server as a domain-specific language (DSL). Clients can use it to send scripts written in your DSL to the server to process and respond to as a batch.”

— Alan Johnson (Is GraphQL The Future?)

Yikes, that probably wasn’t the answer that I (nor you, dear reader) were looking for!

Domain-what-a-thing?

However, as scary as the above definition seems, it is important to unpack it a bit if we want to get to the root of what exactly GraphQL is.

Let’s start with the term ‘domain-specific language’:

  1. First and foremost, a domain-specific language (also called a mini-language) is a programming language created to express a very specific and predefined type of digital information (a domain). Whereas a general purpose language like JavaScript can (similar to a Swiss army knife) be used to express a range of digital information (and in some cases, even information that its creators didn’t anticipate at inception). This includes everything from low-level primitives like objectsfunctionsstringssymbols to general programming patterns like HTTP requestsDOMmanipulations and/or online data storage). Domain-specific languages tend to be more limited (and intentionally so) in what they are able to express when compared to general-purpose programming languages.
  2. Secondly, DSL’s are often plugged into other DSL’s or general purpose languages to piggyback on existing functionality (due to their limited scope). However, this does not mean that DSL’s are tied to specific languages (GraphQL being an example of this). For example, the (more or less defunct now) XForms DSL can be used inside HTML (which itself is a DSL on top of another DSL called SGML), while at the same time it can also be used in a general purpose language like Java.

Is this getting a bit too nerdy?

Right, let’s bring it back! You probably have more experience with DSL’s than you realise (and not only through HTML!), but one or more of the following:

Furthermore, you probably already have first-hand experience of their narrow scope. Most people will roll their eyes if I attempt to manage a database by means of HTML or control a spacesuit via CSS.

The real value of DSL’s

However, because of their very narrow scope, DSL’s tend to be extremely expressive (in other words, easy to read and write) compared to general purpose languages.

As an example:

A friend (and ex-colleague) of mine, Greg Kempe uses a DSL called Akoma Ntoso (built on XML) in his non-profit project called Open By-laws. Akoma Ntoso (meaning ‘linked hearts’ in Akan) is a DSL built exclusively to express parliamentary, legislative and judiciary documents in a digital manner.

For example, see below a section of the city of Cape Town’s outdoor signage by-law (expressed in Akoma Ntoso):

<part id="part-B">
  <num>B</num>
  <heading>Submission of applications</heading>
  <section id="section-1">
     <num>1.</num>
     <subsection id="section-1.subsection-0">
        <content>
           Other than those signs referred to in Sections 55 to 62 hereinbelow, no person shall display any advertisement or erect or use any sign or advertising structure for advertising purposes without the <term refersTo="#term-Municipality" id="trm19">Municipality</term>'s approval in terms of this By-law and any other applicable legislation.
         </content>
      </subsection>
   </section> 
</part>
You can view the full by-law (in Akoma Ntoso) on Github

Bringing this back to front-end development

To illustrate the above in the context of front-end development we can look at a common example where we update our website’s Document Object Model(DOM) via JavaScript (in order to show a specific message when a user is logged in):

const function createUserGreeting = salutation => {
  if (window.user) {
    const image = document.createElement('img');
    
    if (window.innerWidth > 800) {
      image.src = "https://via.placeholder.com/400";
    } else {
      image.src = "https://via.placeholder.com/100";
    }
    
    imgage.alt = "" 
    
    const heading = document.createElement('h1');
    const hello = document.createTextNode(salutation + ' ');
    const strong = document.createElement('strong');
    const world = document.createTextNode('User!');
    
    span.appendChild(hello);
    strong.appendChild(world);
    heading.appendChild(span);
    heading.appendChild(world);
    
    const example = document.createElement('div')
    
    example.className.add('border');
    example.className.add('red');
    example.appendChild(image);
    example.appendChild(heading)
    
    return document.body.appendChild(example);
  }
}

let user = null;
createUserGreeting ('Hello')

user = 'John';
createUserGreeting ('Ahoy')

You can see it in action inside the following Codepen example:

As powerful as JavaScript (even with the above ES6 syntax is), it isn’t very expressive when working with the DOM. Fortunately, there is a DSL specifically designed to better express browser DOM nodes. You might know it as HTML (or by the full name: Hypertext Markup Language).

This means that we can use the innerHTML property (only added to JavaScript back with Internet Explorer 4) to re-write the above. The innerHTML property accepts a string written in HTML DSL:

const createUserGreeting = salutation => {
  if (window.user) {
    document.body.innerHTML = `
      <div class="border red">
        <h1>
          <span>Hello </span>
          <strong>User!</strong>
        <source>
          <srcset media="(max-width: 800px)" width="400" srcset="https://via.placeholder.com/800">
          <img src="https://via.placeholder.com/200" width="100" alt="">
        </source>
      </div>
    `;
  }
}

let user = null;
createUserGreeting ('Hello')

user = 'John';
createUserGreeting ('Ahoy')

As you can see we still get the exact same behaviour:

One last thing

Lastly, before we get into the GraphQL DSL itself, it might be of value to draw a distinction between DSL’s and superset languages like TypeScript or Sass. While a superset language is meant to extend an existing language’s grammar, a DSL does not need to adhere to any underlying language or environment. For example, JSX (built on top of XML) can be used to either interface directly with the browser DOM or a mobile operating system in the form of a mobile app (by means of React Native).

Stop before you type that angry reply! I’m aware that the above distinction between DSLs/general purpose languages and DSLs/superset languages is fuzzy in a lot of cases, and (much like the disputed difference between websites and webapps) is subject to the Sorites paradox. However, as is true with all cases of the Sorites paradox, fuzzy distinctions exist (in spite of their lack of scientific rigour) specifically because of the value they provide when explaining the nature of day-to-day experiences. So let’s merely call the above definition this article’s working definition of DSLs.

What problem is GraphQL trying to solve?

Similar to the above, GraphQL was created internally by the tech team behind Facebook in 2012 as a DSL to write more expressive (and powerful) data queries in the Facebook mobile app (to a remote data API).

The problem: Common REST (or Representational State Transfer) APIapproaches mostly rely on fixed data structures. This means that after enough iteration, most REST API’s end up requiring a Lernaean Hydra of queries to get a specific piece of data.

In short (as noted by Chimezie Enyinnaya, a Nigerian content creator for Pusher — a service that manages remote pub/sub messaging):

“With REST, we might have a /authors/:id endpoint to fetch an author, then another /authors/:id/posts endpoint to fetch the post of that particular author. Lastly, we could have a /authors/:id/posts/:id/comments endpoint that fetches the comments on the posts. […] It is easy to fetch more than the data you need with REST, because each endpoint in a REST API has a fixed data structure which it is meant to return whenever it is hit.”

— Chimezie Enyinnaya (REST versus GraphQL)

In fact, this is so common that GraphQL is just one of several solutions that were conjured up to solve this problem:

“Interestingly, other companies like Netflix or Coursera were working on comparable ideas to make API interactions more efficient. Coursera envisioned a similar technology to let a client specify its data requirements and Netflix even open-sourced their solution called Falcor.”

— How to GraphQL (GraphQL fundamentals: Introduction)

However, contrary to some of the above, GraphQL was released three years later under the MIT license and today forms the backbone behind open-source services like Apollo (using GraphQL to read and/or change both local and remote app state) or even Gatsby (using GraphQL to query front-matter and textual content from markdown files).

So without further ado, let’s get to the meat of this section: A real-world working example that actually illustrates how GraphQL solves the above problem.

For argument’s sake, let’s say that I want to know the number of users following me on Github. We can easily retrieve the data via the native JavaScript fetch method (from the Github REST API), and then display a list of usernames in the DOM via an unordered list (by means of the innerHTMLexample illustrated above):

const addFollower = follower => `<li>${follower.login}</li>`;
const createList = data => document.body.innerHTML = `<ul>{data.map(addFollower)</ul>`;

fetch('https://api.github.com/users/schalkventer/followers')
  .then(response => response.json())
  .then(createList);

Surprisingly straightforward right?

However, getting a list of followers doesn’t really tell us much. We want to get a sense of how prominent these users are on Github (since a follow from Dan Abramov should be weighed differently than a follow from Johnny the team intern). In order to accomplish this, I will be using the extremely unscientific concept, which I henceforth deem Github Equity™ (similar to the search engine concept of Link Equity). Github Equity™ will be calculated by means of the total repositories maintained by a user and their own amount of followers.

In short:

Total Repositories * Total Followers

Pretty easy! However, getting the data required to perform this calculation is a bit trickier since it would require several asynchronous requests REST queries (requiring some orchestration by means of native JavaScript Promises):

const addFollower = ({ name, equity, url }) => `<li><a href="${url}">${name}</a> (${equity})</li>`;
const createListHtml = data => document.body.innerHTML = `<ul>${data.map(addFollower).join('')}</ul>`;

const calcLength = val => val ? val.length : 0;
const calcNestedArraysLength = array => index => array[index];

const createList = (props) => {
  const { 
    response,
    ownFollowers: ownFollowersSource = [],
    repositories: repositoriesSource = [],
  } = props;
  
  const ownFollowersList = ownFollowersSource.map(calcLength);
  const repositoriesList = repositoriesSource.map(calcLength);

  const data =  response.map((follower, index) => {
    return {
      name: follower.login,
      url: follower.html_url,
      equity: ownFollowersList[index] * repositoriesList[index],
    }
  })
  
  return createListHtml(data);
}

const getFollowersInfo = (response) => new Promise((resolve) => {
  const asyncOwnFollowers = response.map((follower) => {
    return new Promise((resolve) => {
      fetch(follower.followers_url)
        .then(response => response.json())
        .then(resolve)
    });
  });
                       
  const asyncRepositories = response.map((follower) => {
    return new Promise((resolve) => {
      fetch(follower.repos_url)
        .then(response => response.json())
        .then(resolve)
    });
  });
  
  const ownFollowersPromise = Promise.all(asyncOwnFollowers);
  const repositoriesPromise = Promise.all(asyncRepositories);
  
  Promise.all([ownFollowersPromise, repositoriesPromise])
    .then(([ownFollowers, repositories]) => resolve({
      response,
      ownFollowers,
      repositories,
    }));
});
    
new Promise((resolve) => {
  fetch(`https://api.github.com/users/schalkventer/followers`)
    .then(response => response.json())
    .then(getFollowersInfo)
    .then(createList);
});

As data queries go the above is still well within the bounds of what would be considered reasonable. However, all the required REST API calls (running in parallel!) make the code extremely hard to read and modify. This means that even if we only get the needed information from the first 10 followers, it would amount to a total of 31 REST API calls. Meaning that we quickly run into the default Github API rate limit (a limit on the amount of request the API accepts from a specific IP in the span of an hour)

You can see this happening in the below Codepen, where it should output the following error to the DOM if run a couple of times in a single hour (click the rerun button in the bottom right corner a couple of times) : TypeError: response.map is not a function. In other words, the API did not return the required array (since .map() can only be run on iterables in JavaScript):

Lucky for us (in addition to the above REST API) Github also exposes a GraphQL endpoint by means of the following: https://api.github/graphql.This means that we can re-write the above as follows in the GraphQL DSL:

const query = `{
  user(login: "schalkventer") {
    id
    followers (first: 100) {
      edges {
        node {
          id
          login
          url
          repositories (first: 100) {
            edges {
              node {
                id
              }
            }
          }
          followers (first: 100) {
            edges {
              node {
                id
              }
            }
          }
        }
      }
    }
  }
}`;

const createListItem = ({ login, url, followers, repositories }) => {
  return`<li><a href="${'url'}">${login}</a> (${followers.edges.length * repositories.edges.length})</li>`;
}

const createHtml = (response) => {
  const list = response.data.user.followers.edges.map(({ node }) => node).map(createListItem).join('');
  document.body.innerHTML = `<ul>${list}</ul>`;
}

const options = {
  method: "post",
  headers: {
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    query,
  })
};

fetch('https://api.github.com/graphql', options)
  .then(res => res.json())
  .then(createHtml);
You can try out the above query on live Github data at https://developer.github.com/v4/explorer/

If you haven’t encountered GraphQL before the above might look a bit bewildering. However, we’ll unpack the syntax a bit in the upcoming section.

As an aside, we are doing a very low-level/hand-rolled implementation of GraphQL for illustrative purposes. When encountering GraphQL in the wild you will most probably encounter it by means of Apollo (developed by the team behind Meteor) or Relay (developed by the team behind Facebook). These libraries are essentially just tooling that makes it easier to work with GraphQL on the client-side.

The GraphQL equivalent of ‘Hello World!’

Queries and Subscriptions and Mutations, Oh my!

Personally for me, when I’m just starting out with a new programming language (even if it’s a DSL like GraphQL) there is often (what seems like) an impossible amount of information to take in. In order to make this process a bit more manageable, I (without fail) always start with the same question: What is to the ‘Hello World!’ equivalent of this language (often followed by what is the To-do app equivalent of this language).

In short:

A “Hello, World!” program generally is a computer program that outputs or displays the message “Hello, World!”. Because it is very simple in most programming languages, it is often used to illustrate the basic syntax of a programming language and is often the first program that those learning to code write.

A “Hello, World!” program is traditionally used to introduce novice programmers to a programming language.

— Wikipedia («Hello, World!” program)

So what is the ‘Hello World!’ equivalent in GraphQL?

According to Julian Mayorga in his book, Fullstack GraphQL, ‘In its simplest form, GraphQL is all about asking for specific fields of objects’. Something called client‐specified queries in the original 2015 GraphQL spec:

These queries are specified at field‐level granularity. In the majority of client‐server applications written without GraphQL, the server determines the data returned in its various scripted endpoints. A GraphQL query, on the other hand, returns exactly what a client asks for and no more.

— GraphQL Working Draft (July 2015)

However, what separates a GraphQL ‘Hello World!’ from (for example) a JavaScript console.log('Hello World!') is that we need to connect our query to something that is queryable.

Luckily there are several public GraphQL endpoints available on the internet. From a Stanford University endpoint that allows one to query HIV drug resistance data to an endpoint that houses a collection of public demographic information arranged by country.

However, let us direct our gaze on the pinnacle of human technological achievement: a Pokéapi that supplies ‘ all the Pokémon data you’ll ever need’.

As a warm-up exercise lets create the following query (you can follow along if you want):

{
  pokemons (first: 20) {
    name
  }
}

Meh! That was quite underwhelming: a list of 20 Pokemon from the Pokedex. However, let’s turn it up a notch and find something more specific (which if you remember correctly is where GraphQL really shines!).

To make it interesting let’s say that we want to determine the average weight of Pikachu’s final evolution (spoiler: it’s Raichu). We can use the following query (link to live example):

const query = `{
  pokemon(name: "Pikachu") {
    evolutions {
      weight {
        minimum
        maximum
      }
    }
  }
}`;

const parse = (response) => {
  const evolutionArray = response.data.pokemon.evolutions;
  const finalEvolution = evolutionArray[evolutionArray.length - 1];
  const { minimum, maximum } = finalEvolution.weight;
  return (parseInt(minimum) + parseInt(maximum)) / 2;
}

const createHtml = (response) => document.body = parse(response);

const options = {
  method: "post",
  headers: {
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    query,
  })
};

fetch('https://graphql-pokemon.now.sh', options)
  .then(res => res.json())
  .then(createHtml);

It is important to note that the above query is essentially shorthand for the following:

query GetPikachuEvolutionWeight {
  pokemon(name: "Pikachu") {
    evolutions {
      weight {
        minimum
        maximum
      }
    }
  }
}

The fact that GraphQL assumes you will be doing a query even when you don’t specify an action shows how central queries are to GraphQL.

Regardless, no matter which of the above we use, we will get the following JSON response from the endpoint:

{
  "data": {
    "pokemon": {
      "evolutions": [
        {
          "weight": {
            "minimum": "26.25kg",
            "maximum": "33.75kg"
          }
        }
      ]
    }
  }
}

This means that we can just run our parse() function (from the above example) on this JSON response, and output the result (29.5) to the DOM.

In short, it can be said that queries are little maps in the form of Strings (no, not this kind!) used by GraphQL to navigate a data-structure to find all requested items in a single journey.

This means that we can (for the fun of it) write a similar set of real-world instructions in the GraphQL DSL:

{
  "data": {
    "pokemon": {
      "evolutions": [
        {
          "weight": {
            "minimum": "26.25kg",
            "maximum": "33.75kg"
          }
        }
      ]
    }
  }
}
I’m calling it — 2028 robot servants will be programmed with GraphQL.

In what order should I learn GraphQL concepts?

Thus far we’ve only touched on queries. However (and perhaps surprisingly), you can get pretty far with GraphQL by just understanding the above. However, there are several additional concepts that you might want to look into if you want to use GraphQL to its full potential:

Additional tooling/concepts used by GraphQL queries:

  1. Fields: This is the items in a query that at face-value resemble keys in a JavaScript object. For example paper , post_office and travel in the above example.
  2. Arguments: Optional information we can pass to fields. For example type: drive and amount: 12 in our example above.
  3. Aliases: A custom name that should be used for the JavaScript key to which a field resolves. By default, the object key is the same name as the field. For example in the above post_office will resolve to { post_office: { ... } } . However, we can alias it as follows: postOffice: post_office , which will return { postOffice: { ... } } . Not only is this useful if we want to make the key more semantic or change the casing, but this is also useful when we are using the same field twice (to prevent the default key of the second post_office from overriding the first post_office value.
  4. Variables: When I first started using GraphQL, I did what any reasonable developer would do. I just used dynamic interpolation in the query (expressed through a template literal). In other words, I would do the following for our Pokemon example above: pokemon (name: "${dynamicValue)"). Much to the shock of fellow GraphQL developers (since I’m essentially creating side-effects all over the place)! Turns out that GraphQL has built-in functionality to pass external values into a query. By declaring the variable at the query root. For example with query GetPokemonEvolutionWeight($name: string) and pokemon (name: $name)we can simply pass an object of variables to the query when it gets called (i.e. { name: 'Pikachu' } . Note that you need to assign one of the core GraphQL scalar types to a variable (for example we used string above). It is possible to create your own custom types, but this is outside of the scope of this article.

Furthermore, you might also be interested in venturing past queries only (covered in this article) into more advanced GraphQL features:

  • Mutations: Thus far we’ve only been fetching data via GraphQL. However, it is also possible to send data via GraphQL. This is done via Mutations, which are the GraphQL equivalent of POST in traditional REST API endpoints.
  • Subscriptions: This is essentially traditional GraphQL queries in reverse. Instead of sending a request to the server to retrieve data we tell the server to let us know when data changes and to send the updated data to us as defined in the subscription.

What about the back-end?

In short, when I initially asked myself this question 3 years ago the answer was a resounding:

Don’t even worry about it.

Furthermore, I’m not sure whether my response has changed since. I still have no idea what Gatsby does behind the scenes to convert my markdown (via gatsby-transformer-remark) and JSON (via gatsby-transformer-json) content into a GraphQL endpoint.

This is not due to apathy, quite the contrary in fact! I’m a big fan of Gatsby and busy working on a pull request to trigger prefetching of pages programmatically. Given how self-documenting GraphQL is, I have yet to have a need to peek under the hood in terms of how Gatsby handles GraphQL — regardless of how complex my query or data gets. Furthermore, there are several other GraphQL services that I use (for example GraphCMS) where I can say the exact same.

Does this mean that there is no value in learning how to configure a GraphQL server?

Certainly not!

As with anything understanding how something works under the surface (whether it be JavaScript, CSS or even the browser itself) makes it easier to debug things when they do go wrong. However, the fact that I’ve only started digging into the back-end side of GraphQL recently goes to show how far you can get without knowing anything about how the endpoint gets created behind the scenes.

However, if you are interested in learning how to set up a custom GraphQL server you can have a look at GraphQL for Back-end Developers by my good friend Shailen Naidoo. He is a phenomenal developer and the reason why I’m even looking at the back-end side of GraphQL in the first place.

Final Word

First and foremost, well done if you’ve read this entire wall of text from top to bottom. It’s quite lengthy! I started writing it mostly in response to the lack of front-end specific introductions to GraphQL. This meant that there was quite a bit of ground to cover.

Secondly, I am by no means an expert on GraphQL so if there are resources/references that I missed or you feel would help front-end developers get started on GraphQL, then please let me know in the comments. I’m more than happy to add it.

Lastly, if there are any inaccuracies also feel free to call me out in the comments!

If you’re interested in learning more about GraphQL check out the following resources:

Lastly, thanks for the feedback and input provided by Shailen Naidoo and Zeeshaan Maudarbocus.

Follow me on Github, I’m always curious as to what everyone in the tech field is working on — so I’ll probably follow you back! 😊

Written by

Go to the profile of Schalk Venter

Schalk Venter

Medium member since Jun 2019

🔧 Front-end Development / 🎨 User Interface Design / 🌍 Social Good / ❤️ De-stigmatising Mental Illness

freeCodeCamp.org

freeCodeCamp.org

This is no longer updated. Go to https://freecodecamp.org/newsinstead