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

Share this article

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.

Key Takeaways

  • GraphQL provides a common interface between the client and the server for data fetching and manipulations, allowing the client to describe the data it needs and its shape, making data retrieval more efficient.
  • GraphQL.js, a JavaScript implementation of GraphQL, is used to build a type schema and serve queries against that type schema. The schema makes no assumptions about how the data is stored, only describing what the consumer of the API can use.
  • React, a JavaScript library for creating user interfaces, can be used as the front-end framework for a GraphQL server. It is all about building reusable components and is ideal for large applications with data that changes over time.
  • GraphQL queries can be used for fetching data from the server and for manipulating data (create, update, delete). Mutations in GraphQL are operations intended to have side effects and are used to add and change data.

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.

Frequently Asked Questions about GraphQL

What are the main differences between GraphQL and REST?

GraphQL and REST are both APIs that allow you to access data from a server. However, they differ in several ways. GraphQL allows you to request specific data, reducing the amount of data that needs to be transferred over the network. This can lead to performance improvements. On the other hand, REST APIs often require loading from multiple URLs, which can be slower and more inefficient. Additionally, GraphQL supports real-time updates with subscriptions, while REST does not.

How does GraphQL handle errors?

Unlike REST, which uses HTTP status codes to indicate errors, GraphQL only uses the 200 OK status, even when an error occurs. Errors are included in the response body, under the “errors” field. Each error object in the array has a “message” field, which provides a human-readable error message. This approach allows GraphQL to provide detailed error information, even when multiple errors occur in a single request.

Can I use GraphQL with any database?

Yes, GraphQL can be used with any database or back-end service that can be accessed with JavaScript. GraphQL is not tied to a specific database or storage engine and is instead backed by your existing code and data.

What is a GraphQL schema?

A GraphQL schema is a contract between the client and the server that defines how a client can access the data. It describes the types of data you can query, including fields, interfaces, unions, and enums. The schema also defines the relationships between these types.

How does GraphQL handle security?

GraphQL itself does not come with built-in authorization or authentication features. Instead, it’s up to you to implement these features at the application level. This can be done using middleware at the GraphQL server level, or by implementing authorization logic inside your GraphQL schema.

What are GraphQL mutations?

In GraphQL, mutations are operations that can modify server-side data. They are similar to the “PUT”, “POST”, “PATCH” and “DELETE” methods in REST. Mutations allow you to create, update, and delete data.

What is Apollo Client and how does it work with GraphQL?

Apollo Client is a comprehensive state management library for JavaScript that enables you to manage both local and remote data with GraphQL. Apollo Client uses GraphQL to fetch, cache, and modify application data, all while automatically updating your UI.

Can I use GraphQL without a client library?

Yes, you can use GraphQL without a client library. You can make HTTP requests directly to a GraphQL server using tools like fetch or axios. However, client libraries like Apollo Client or Relay can provide additional features like caching and optimistic UI updates.

What are GraphQL subscriptions?

GraphQL subscriptions are a way to push data from the server to the clients. They are useful when you want to notify a client about real-time updates, such as new messages in a chat application.

How can I test a GraphQL API?

You can test a GraphQL API using a variety of tools. One popular tool is GraphiQL, an in-browser IDE that allows you to write, validate, and test GraphQL queries. Other tools include Apollo Client Developer Tools and GraphQL Playground.

Igor Ribeiro LimaIgor Ribeiro Lima
View Author

Igor works as UI Engineer on Avenue Code, and is a writer in his spare time. He enjoys learning new things, working on personal projects and contributing to open source community.

AurelioDgraphqljavascriptReacttodo
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week