Friday, 24 May, 2019 UTC


Summary

In this tutorial, we’ll learn to build a GraphQL API server with Node.js and Express.
You can find the final code for this example in this GitHub repository.
Before building our GraphQL API, let’s first introduce GraphQL and the advantages it offers over the REST way of building APIs.
What is GraphQL
GraphQL is both a runtime and a query language for building web APIs. It allows developers to provide a complete description of data used in your application which enables clients to query for exactly the data they need nothing more.
Advantages of GraphQL
Big companies like Facebook, IBM, GitHub and Twitter migrated from REST to GraphQL APIs because of its many advantages. Let’s briefly see some of them:
  • GraphQL allows developers to send a single request for fetching data that may require consuming multiple REST endpoints. This means developers have to write less code which increases productivity. According to the PayPal Engineering team*, UI developers were spending less than 1/3 of their time actually building UI.
  • GraphQL provides better performance as a result of less network overhead since you can describe the data you want in one query and send/receive fewer network requests and responses.
  • Support for nested data which makes sending complex queries easier than REST.
Prerequisites
In order to follow this tutorial from scratch, you should have:
  • Knowledge of JavaScript and familiarity with Node.
  • Node and NPM installed on your development machine. You can head to the official website to download the binaries required for your system or use NVM to install Node.js.
If you have these prerequisites, you are good to go!
Setting up the Project
Let’s now set up our project. Open a new terminal and execute the following commands to create a package.json file with default values:
mkdir node-graphql-demo  
cd node-graphql-demo  
npm init -y  
Next, we need to install the following dependencies:
npm install  graphql express express-graphql sqlite3 --save  
This will install the Express framework, the GraphQL implementation for Node.js, the GraphQL middleware for Express and SQLite3.
To make things simple, we’ll be using SQLite3 for the database.
Create the GraphQL Server
Now that we have a project set up with the required dependencies, let’s create the API server. In your project’s folder, create an index.js file and add the following imports:
const express = require('express');  
const sqlite3 = require('sqlite3').verbose();  
const graphql = require("graphql");  
const ExpressGraphQL = require("express-graphql");  
We’re importing Express, SQLite3, GraphQL and GraphQL middleware for Express.
Next, add the following code to create an Express app and a SQLite 3 database called my.db in the current folder:
const app = express();  
const database = new sqlite3.Database("./my.db");  
Next, add the createContactTable() method which creates a contacts table in the database and call the function immediately:
const createContactTable = () => {  
    const query = `
        CREATE TABLE IF NOT EXISTS contacts (
        id integer PRIMARY KEY,
        firstName text,
        lastName text,
        email text UNIQUE)`;
    return database.run(query);
}
createContactTable();  
We created a SQL table to store contacts. Each contact has a unique identifier, first name, last name, and email.
Next, add the following code to define a GraphQL type:
const ContactType = new graphql.GraphQLObjectType({  
    name: "Contact",
    fields: {
        id: { type: graphql.GraphQLID },
        firstName: { type: graphql.GraphQLString },
        lastName: { type: graphql.GraphQLString },
        email: { type: graphql.GraphQLString }   
    }
});
We use the basic built-in GraphQL types such as [GraphQLID](https://graphql.github.io/graphql-spec/draft/#sec-ID) and [GraphQLString](https://graphql.github.io/graphql-spec/draft/#sec-String) to create our custom type that corresponds to a contact in the database.
Next, define the query type as follows:
var queryType = new graphql.GraphQLObjectType({  
    name: 'Query',
    fields: {
        contacts: {
            type: graphql.GraphQLList(ContactType),
            resolve: (root, args, context, info) => {
                return new Promise((resolve, reject) => {

                    database.all("SELECT * FROM contacts;", function (err, rows) {
                        if (err) {
                            reject([]);
                        }
                        resolve(rows);
                    });
                });

            }
        },
        contact: {
            type: ContactType,
            args: {
                id: {
                    type: new graphql.GraphQLNonNull(graphql.GraphQLID)
                }
            },
            resolve: (root, {
                id
            }, context, info) => {
                return new Promise((resolve, reject) => {

                    database.all("SELECT * FROM contacts WHERE id = (?);", [id], function (err, rows) {
                        if (err) {
                            reject(null);
                        }
                        resolve(rows[0]);
                    });
                });
            }
        }
    }
});
Our query has two fields: contacts, that can be used to get all the contacts in the database, and contact, used to get a single contact by id. The contact field accepts a required id argument of type GraphQLID.
Each field can have a type, which specifies the type of the returned data, args for specifying any arguments expected from the client, and resolve, which specifies the actual method that executes the logic for fetching data.
For both fields, the resolve() method is where the actual logic happens — we simply call database.all() or database.run() methods to execute the right SQL query for fetching data from SQLite and we return a Promise that resolves to the fetched data.
We can access any passed arguments from the second parameter of the resolve() method.
Next, let’s create a mutation type that corresponds to the create, update and delete operations:
var mutationType = new graphql.GraphQLObjectType({  
    name: 'Mutation',
    fields: {
        createContact: {
            type: ContactType,
            args: {
                firstName: {
                    type: new graphql.GraphQLNonNull(graphql.GraphQLString)
                },
                lastName: {
                    type: new graphql.GraphQLNonNull(graphql.GraphQLString)
                },
                email: {
                    type: new graphql.GraphQLNonNull(graphql.GraphQLString)
                }
            },
            resolve: (root, {
                firstName,
                lastName,
                email
            }) => {
                return new Promise((resolve, reject) => {
                    database.run('INSERT INTO contacts (firstName, lastName, email) VALUES (?,?,?);', [firstName, lastName, email], (err) => {
                        if (err) {
                            reject(null);
                        }
                        database.get("SELECT last_insert_rowid() as id", (err, row) => {

                            resolve({
                                id: row["id"],
                                firstName: firstName,
                                lastName: lastName,
                                email: email
                            });
                        });
                    });
                })

            }
        },
        updateContact: {
            type: graphql.GraphQLString,
            args: {
                id: {
                    type: new graphql.GraphQLNonNull(graphql.GraphQLID)
                },
                firstName: {
                    type: new graphql.GraphQLNonNull(graphql.GraphQLString)
                },
                lastName: {
                    type: new graphql.GraphQLNonNull(graphql.GraphQLString)
                },
                email: {
                    type: new graphql.GraphQLNonNull(graphql.GraphQLString)
                }
            },
            resolve: (root, {
                id,
                firstName,
                lastName,
                email
            }) => {
                return new Promise((resolve, reject) => {
                    database.run('UPDATE contacts SET firstName = (?), lastName = (?), email = (?) WHERE id = (?);', [firstName, lastName, email, id], (err) => {
                        if (err) {
                            reject(err);
                        }
                        resolve(`Contact #${id} updated`);

                    });
                })
            }
        },
        deleteContact: {
            type: graphql.GraphQLString,
            args: {
                id: {
                    type: new graphql.GraphQLNonNull(graphql.GraphQLID)
                }
            },
            resolve: (root, {
                id
            }) => {
                return new Promise((resolve, reject) => {
                    database.run('DELETE from contacts WHERE id =(?);', [id], (err) => {
                        if (err) {
                            reject(err);
                        }
                        resolve(`Contact #${id} deleted`);

                    });
                })

            }
        }
    }
});
Our mutation type has three fields:
  • createContact for creating contacts;
  • updateContact for updating contacts;
  • deleteContact for deleting contacts.
All fields accept arguments which are specified in the args property and have a resolve() method that takes the passed arguments, executes the corresponding SQL operation, and then returns a Promise.
Next, create a GraphQL schema as follows:
const schema = new graphql.GraphQLSchema({  
    query: queryType,
    mutation: mutationType
});
A GraphQL schema is a core concept of GraphQL and it describes the functionality available to the clients which connect to the server. We pass the query and mutation types we defined earlier to the schema.
Finally, mount the /graphql endpoint and run the Express server on the 4000 port:
app.use("/graphql", ExpressGraphQL({ schema: schema, graphiql: true}));  
app.listen(4000, () => {  
    console.log("GraphQL server running at http://localhost:4000.");
});
Save your index.js file and head back to your terminal. Then, run the following command to start the server:
node index.js  
How to Consume the GraphQL API
Before building a client, you can use the GraphQL interface to test your API.
Go to the http://localhost:4000/graphql address and run the following mutation query:
mutation {  
    createContact(firstName: "Jon", lastName: "Snow", email: "[email protected]") {
        id,
        firstName,
        lastName,
        email
    }
}
You can update a contact with id 1 using the following mutation:
mutation {  
    updateContact(id: 1, firstName: "Aegon", lastName: "Targaryen", email: "[email protected]")
}
And also delete this contact with id 1 using the following mutation:
mutation {  
    deleteContact(id: 1)
}
Finally, you can get all contacts in the database using the following query:
query {  
    contacts {
        id
        firstName
        lastName
        email
    }
}
And you can get a single contact using this query:
query {  
    contact(id: 1) {
        id
        firstName
        lastName
        email
    }
}
Here, we get the contact with the id: 1.
Conclusion
In this tutorial, we’ve used Node and Express.js to create a simple GraphQL API for reading, creating, updating and deleting contacts from an SQLite database.
We’ve seen that GraphQL is both a runtime and a query language for building web APIs that has many advantages over the REST approach.
We’ve also seen how to work with basic built-in types in GraphQL and used them to create our own query and mutation types for both reading and mutating data.
Finally, we’ve seen how to use the GraphQL interface to execute queries and mutations against our API.
Lastly, if you want to learn how you can secure your JavaScript source code against theft and reverse-engineering, you can try Jscrambler for free.