Build a GraphQL API with Node
May 24th, 2019 | By Ahmed Bouchefra | 6 min read
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 introduce GraphQL and its advantages over the REST way of building APIs.
What is GraphQL
GraphQL is a runtime and a query language for building web APIs. It allows developers to provide a complete description of data used in your application, enabling clients to query for exactly the data they need.
Advantages of GraphQL
Big companies like Facebook, IBM, GitHub, and Twitter migrated from REST to GraphQL APIs because of their 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 spent less than 1/3 of their time building UI.
GraphQL provides better performance by its 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
To follow this tutorial from scratch, you must have:
Knowledge of JavaScript and familiarity with Node.
Node and NPM are 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 calls 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 an 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](/graphql-spec/draft/#sec-ID) and [GraphQLString](/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, which can be used to get all the contacts in the database, and contacts, 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 that 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]")
}
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
}
}
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. Feel free to move on to the next part of this tutorial, where we build a Vue app and perform GraphQL queries.
Jscrambler
The leader in client-side Web security. With Jscrambler, JavaScript applications become self-defensive and capable of detecting and blocking client-side attacks like Magecart.
View All ArticlesMust read next
Getting Started with GraphQL
GraphQL is a declarative, compositional, and strong-typed query language. Useful for querying dynamic data with a strong-typed schema.
May 11, 2016 | By Camilo Reyes | 4 min read
Developing An Isomorphic GraphQL App With React
Check more info about isomorphic programming in JavaScript with this short demo, while leveraging React and GraphQL
July 21, 2016 | By João Carvalho | 4 min read