JavaScript
Article

GraphQL Overview: Build a to-Do List API with a React Front-End

By Igor Ribeiro Lima

This article was peer reviewed by Panayiotis «pvgr» Velisarakos. Thanks to all of SitePoint’s peer reviewers for making SitePoint content the best it can be!

Imagine you want to bake a cake by following a recipe. You’ll need a few ingredients, and a right quantity for each of them. What if you could get a box with all the ingredients your recipe requires, already measured and weighted to match your recipe? It surely would make baking much easier. This is what GraphQL is meant to do, if you imagine the front-end UI as a cake.

In this tutorial we’ll write a small GraphQL server to respond to requests from a Todo List app. You can choose among many apps over there but since I’m working at a React project these days, I’ll pick React as the front-end framework. However, feel free to choose any other JavaScript framework you’re comfortable with.

GraphQL

GraphQL allows us to define a query that provides a common interface between the client and the server for data fetching and manipulations. It deals with a query language that allows the client to describe the data it needs and its shape, which is designed to build client applications by providing an intuitive and flexible syntax.

This makes retrieving data from the server more efficient for the client. For instance, imagine the client needs nothing else than a title and an id from an implementation of GraphQL, then it should do something like this:

query Query {
  todos {
    id,
    title
  }
}

Which produces the resulting data (in JSON):

{
  "data": {
    "todos": [
      {
        "id": 1446412739542,
        "title": "Read emails"
      },
      {
        "id": 1446412740883,
        "title": "Buy orange"
      },
      {
        "id": 1446412741215,
        "title": "Fix garbage"
      }
    ]
  }
}

Maybe there is no data saved yet in our live demo. The reason behind this is that every time we run the server, the array in memory that stores the Todo(s) becomes empty. We’ll see how to add data in that array in the following sections.

As seen, the response format is described in the query and defined by the client instead of the server. As stated in the article titled “GraphQL Overview – Getting Started with GraphQL and Node.js”,

GraphQL queries are like JSON objects without properties. It’s important to mention that GraphQL is not language specific, it’s just a specification between the client and the server. Any client should be able to communicate with any server if they speak the common language.

Introducing GraphQL.js

GraphQL.js is a reference implementation of GraphQL for JavaScript, and it provides two important capabilities:

  1. Building a type schema.
  2. Serving queries against that type schema.

It’s needed to build a GraphQL type schema which maps to the code base. In the code that follows, we define a simple schema. It has one type and a list of Todo(s) (where each elements has three fields) that resolves to a fixed value. In addition, it’s needed to serve the result of a query against that type schema.

var graphql = require ('graphql');

// Here is some dummy data to make this piece of code simpler.
// It will be changeable after introducing mutation.
var TODOs = [
  {
    "id": 1446412739542,
    "title": "Read emails",
    "completed": false
  },
  {
    "id": 1446412740883,
    "title": "Buy orange",
    "completed": true
  }
];

var TodoType = new graphql.GraphQLObjectType({
  name: 'todo',
  fields: function () {
    return {
      id: {
        type: graphql.GraphQLInt
      },
      title: {
        type: graphql.GraphQLString
      },
      completed: {
        type: graphql.GraphQLBoolean
      }
    }
  }
});

var queryType = new graphql.GraphQLObjectType({
  name: 'Query',
  fields: function () {
    return {
      todos: {
        type: new graphql.GraphQLList(TodoType),
        resolve: function () {
          return TODOs;
        }
      }
    }
  }
});

module.exports = new graphql.GraphQLSchema({
  query: queryType
});

Let’s now take a look at the code of the JavaScript file that gives us the result data in JSON:

var graphql = require ('graphql').graphql
var express = require('express')
var graphQLHTTP = require('express-graphql')
var Schema = require('./schema')
var query = 'query { todos { id, title, completed } }'

graphql(Schema, query).then( function(result) {
  console.log(JSON.stringify(result));
  // Prints
  // {
  //   "data":{
  //     "todos":[
  //       {
  //         "id":1446412739542,
  //         "title":"Read emails",
  //         "completed":false
  //       },
  //       {
  //         "id":1446412740883,
  //         "title":"Buy orange",
  //         "completed":true
  //       }
  //     ]
  //   }
  // }
});

var app = express()
  .use('/', graphQLHTTP({ schema: Schema, pretty: true }))
  .listen(8080, function (err) {
    console.log('GraphQL Server is now running on localhost:8080');
  });

The same result given by the code above can be obtained by running the code that follows. cURL is not mandatory to get further advantages on this example. It’s just a simpler way to retrieve data without hitting our example in the browser. Please note that in case you are a Window user, you can use the Windows command prompt to run the cURL examples. Moreover, here you can find a good resource to learn how to install cURL on your system.

$ curl -XPOST -H "Content-Type:application/graphql"  -d 'query { todos { title } }' http://localhost:8080
{
  "data": {
    "todos": [
      {
        "title": "Read emails"
      },
      {
        "title": "Buy orange"
      }
    ]
  }
}

An important thing about the schema is that it makes no assumptions about how the data is stored, since it only describes what the consumer of the API can use. The way the data is stored and represented is an implementation detail.

React

React is a JavaScript library for creating user interfaces developed by Facebook and Instagram. Many people choose to think of React as the V in the MVC pattern. As stated on the official website,

we built React to solve one problem: building large applications with data that changes over time. It’s all about building reusable components. In fact, the only thing is build components.

If you need a guide to React, you can read and watch the following resources:

A Simple React Component

React components implement a render() method that takes input data and returns what to display. This example uses an XML-like syntax called JSX. JSX is optional and not required to use React. JSX is a JavaScript syntax extension that looks similar to XML. You can use a simple JSX syntactic transform with React.

Input data passed into the component can be accessed by render() via this.props. A simple example of how to create a React component is reported below and it’s also available as a CodePen.

var Application = React.createClass({
  render: function() {
    return 
{ this.props.text } { this.props.id }
; } });

With the previous code in place, this is the raw JavaScript code produced by the JSX compiler.

"use strict";
var Application = React.createClass({
  displayName: "Application",
  render: function render() {
    return React.createElement(
      "div",
      null,
      this.props.text,
      this.props.id
    );
  }
});

a simple react component

If you want to dig a bit more into React components, take a minute and watch the video An Introduction to Component State.

A Walk-through in Our Example

First of all we need a server (up and running) to receive our GraphQL queries from the Todo List app. This server has already been written above.

To run our server, execute on the CLI:

$ git clone https://github.com/sitepoint-editors/todo-graphql-server.git
$ cd todo-graphql-server
$ npm install
$ npm start

running server locally

You must have Node v4.0.0 or above because the server code uses ES2015 features that are not supported by older versions.

Any POST requests to the endpoint /graphql will now be executed against our GraphQL schema. To test that things are working, type the following code:

$ curl -XPOST -H "Content-Type:application/graphql"  -d 'query { todos { title } }' http://localhost:8080
{
  "data": {
    "todos": []
  }
}

There is no data saved yet. So, every time we run the server, the array in memory that stores the todo(s) becomes empty. Of course we don’t want read-only access to an empty array. We have to add and change data. This kind of operations, which are intended to have side effects, are called mutations in GraphQL. To define a mutation is identical to define a query, and also returns a typed value. The idea is that if something was mutated, then it would return whatever was mutated.

var MutationAdd = {
  type: new GraphQLList(TodoType),
  description: 'Add a Todo',
  args: {
    title: {
      name: 'Todo title',
      type: new GraphQLNonNull(GraphQLString)
    }
  },
  resolve: (root, {title}) => {
    TODOs.push({
      id: (new Date()).getTime(),
      title: title,
      completed: false
    });
    return TODOs;
  }
};

var MutationType = new GraphQLObjectType({
  name: 'Mutation',
  fields: {
    add: MutationAdd
  }
});

export var Schema = new GraphQLSchema({
  query: QueryType,
  mutation: MutationType
});

The arrow above (=>) is the new syntax to define function. One of the most interesting new parts of ES2015.

As explained in the article titled “Your First GraphQL Server” written by Clay Allsopp,

The meaningful difference between a mutation and a query is that mutations are processed serially, but queries make no such guarantee (in fact, GraphQL encourages servers to exploit the inherent parallelism of independent queries). The GraphQL spec gives this example of a set of mutation queries that must be processed by the server in order:

{
  first: changeTheNumber(newNumber: 1) {
    theNumber
  },
  second: changeTheNumber(newNumber: 3) {
    theNumber
  },
  third: changeTheNumber(newNumber: 2) {
    theNumber
  }
}

Therefore, by the end of the request, theNumber field should have the value of 2. After this quick introduction about mutation, we can finally add one todo into our server.

$ curl -XPOST -H "Content-Type:application/graphql" -d 'mutation { add (title: "Clean garage") { id, title } }' http://localhost:8080
{
  "data": {
    "add": [
      {
        "id": 1446443172937,
        "title": "Clean garage"
      }
    ]
  }
}

playing with the server

It is cool, isn’t it? We have much more besides this add mutation: toggle, toggleAll, destroy, clearCompleted. and save. One thing to note is that we are passing arguments in all the mutations. All the fields can accept arguments. Creating arguments is quite simple, and they can be caught in the function resolve.

At the end of the day, we have two types of queries:

  • one for fetching (get) data from the server;
  • one for manipulating (create, update, delete) data.

With a running server, we are ready to use our Todo List made in React: a fork of React TodoMVC Example, as it has been mentioned at the beginning. To download it, execute:

$ git clone -b react-graphql https://github.com/sitepoint-editors/todomvc.git
$ cd todomvc
$ npm install
$ node server.js

Go to http://localhost:3000 to see the running application. This code has two major changes in comparison to the original one. Firstly, the TodoModel has been changed to reach the GraphQL server.

react component model

Secondly, a proxy in the server to redirect GraphQL requests to the server we have created. For further details, see the images below.

server proxy

Moreover, you can find a demo here and here.

graphql overview

Conclusions

As you have seen in this tutorial, GraphQL and GraphQL.js are pretty new technologies released by Facebook as a set of open source projects in 2015. The core idea is that the UI knows best what data it needs to render a particular set of components. If you have tried to pick another JS framework from MVC Todo List and faced any issue, feel free to drop a line. Thanks for reading.

  • http://www.thecheesyanimation.com Bailey Kosky

    I think there’s a copy&paste error in the named query code example. The second ‘findUser’ should be just ‘user’.

    • Igor Ribeiro Lima

      I didn’t see that copy&spate error. I took a look at the article and didn’t see any. Also, I took a look at the live demo and no issue as well. Could you point me where did you see this?

    • Igor Ribeiro Lima

      I didn’t see that copy&spate error. I took a look at the article and didn’t see any. Also, I took a look at the live demo and no issue as well. Could you point me where did you see this?

  • neuruss

    It’s always the same! Someone creates a tutorial for learning about X, and it ends up being a tutorial that requires knowing Y and Z to follow the X tutorial.

  • katopz

    I got “Int cannot represent non 32-bit signed integer value: 1474540692778” when try to add new item. Any hint?

    • katopz

      nvm, Seem like I’ve to use String instead.

Recommended

Learn Coding Online
Learn Web Development

Start learning web development and design for free with SitePoint Premium!

Get the latest in JavaScript, once a week, for free.