How to Create a Secure Node.js GraphQL API
GraphQL is a query language for APIs, originally developed by Facebook for internal use. Since its public release, GraphQL has been compared to REST and other architectures.
In this article, Toptal JavaScript Developer Marcos Henrique da Silva demonstrates how to create a GraphQL Node.js API, and explains why you should try it, too.
GraphQL is a query language for APIs, originally developed by Facebook for internal use. Since its public release, GraphQL has been compared to REST and other architectures.
In this article, Toptal JavaScript Developer Marcos Henrique da Silva demonstrates how to create a GraphQL Node.js API, and explains why you should try it, too.
Marcos is passionate about REST architecture, Agile development, and JavaScript. He has 8+ years of experience focusing on web apps.
In this article, we aim to present a quick guide on how to create a secure Node.js GraphQL API.
Some questions that may come to mind could be:
- What is the purpose of using a GraphQL API?
- What is a GraphQL API?
- What is a GraphQL query?
- What is the benefit of GraphQL?
- Is GraphQL better than REST?
- Why do we use Node.js?
All those are valid questions, but before answering them, we should dive into a brief overview of the current state of web development:
- Almost every solution that you will find today uses some kind of application programming interface (API).
- Even if you just use a social network, such as Facebook or Instagram, you are still connected to a front-end that consumes an API.
- If you are curious, you will find that almost all online entertainment services use a different kind of API, including services like Netflix, Spotify, and YouTube.
In virtually every scenario, you will find an API that you don’t need to know in detail, e.g., you don’t need to know how they were built, and you don’t need to use the same technology they used to be able to integrate it into your own system. The API that is provided allows you to offer a way to communicate between services in a common standard that both the service and the client can communicate without having to depend on a specific technology stack.
With a well-structured API, it is possible to have a solid, maintainable, and scalable API that can serve multiple kinds of clients and front-end applications.
That Said, What Is GraphQL API?
GraphQL is a query language for APIs, developed for internal use in Facebook and published for public use in 2015. It supports reading, writing, and real-time updates. It is also open source, and it is commonly compared to REST and other architectures. It is, in a nutshell, based on:
- GraphQL Queries - This allows the client to read and manipulate how the data should be received.
- GraphQL Mutations - This is how to write data on the server. It is the GraphQL convention on how to write data into the system.
Although this article is supposed to demonstrate a simple, yet real-world scenario on how to build and use GraphQL APIs, we will not provide a detailed introduction into GraphQL. The reason is simple, as the GraphQL team provides comprehensive documentation and lists several best practices in their Introduction to GraphQL.
What Is a GraphQL Query?
As described before, a query is the way that a client can read and manipulate data from the API. You can pass the type of an object and select which kind of fields you want to receive back. A simple query would be like the following:
query{
users{
firstName,
lastName
}
}
In this query, we are trying to reach all users from our users’ schema but only receiving firstName
and lastName
. The result of this query would be like, for example:
{
"data": {
"users": [
{
"firstName": "Marcos",
"lastName": "Silva"
},
{
"firstName": "Paulo",
"lastName": "Silva"
}
]
}
}
It is quite simple for client usage.
What Is the Purpose of Using a GraphQL API?
The purpose of creating an API is the ability to have software as a service that can be integrated by other external services. Even if your application is consumed by a single front-end, you can consider this front-end as an external service, and for that, you will be able to work in different projects when the communication between the two is provided via the API.
If you work in a large team, it can be split up to create a front-end and back-end team, allowing both to use the same technology and make their jobs easier. When architecting an API, it is important to choose the better fit for the project and what brings you closer to your desired solution.
In this article, we will be focusing on a skeleton for building an API that uses GraphQL.
Is GraphQL Better Than REST?
It may be a bit of a cop-out, but I can’t help it: That depends.
GraphQL is an approach that fits several scenarios very well. REST is an architecture approach that is proven in several scenarios as well. Nowadays, there are tons of articles that explain why one is better than the other or why you should use only REST instead of GraphQL. And also, a lot of ways that you can use GraphQL internally and still maintain the API’s endpoints as a REST-based architecture.
The best guidance would be to know the benefits of each approach, analyze the solution you are creating, evaluate how comfortable your team is working with the solution, and assess whether or not you will be able to guide your team to learn and get up to speed fast before choosing between approaches.
This article is more of a practical guide rather than a subjective comparison of GraphQL and REST. In case you’d like to read a detailed comparison of the two, I suggest you check out another one of our articles, GraphQL vs. REST - A GraphQL Tutorial.
In today’s article, we will focus on creating a GraphQL API using Node.js.
Why Do We Use Node.js?
GraphQL has several different libraries you can use. For the purpose of this article, we decided to go with the idea of using JavaScript with Node.js due to their widespread use and the fact that Node.js allows developers to use familiar front-end syntax for server-side development.
It is also useful to compare with our approach with a REST-based API, similar to the one that was demonstrated in another Toptal Engineering Blog article: Creating a Secure REST API in Node.js. This article also showcases the use of Node.js with Express to develop a skeleton REST API which will allow you to compare some differences between these two approaches. Node.js was also designed with scalable network applications, a global community, and several open-source libraries that you can find at the npm website.
This time around, we are going to show how to build a skeleton API with GraphQL, Node.js, and Express!
Hands on GraphQL Tutorial
As outlined earlier, we’ll be building a skeleton idea for GraphQL API, and you will need to know the basics of Node.js and Express before proceeding. The source code of the project made for this GraphQL example is available here.
We are going to handle two types of resources:
- Users, for which we will handle a basic CRUD.
- Products, for which we will have a bit of detail to show more of the power of GraphQL.
The users will contain the following structure:
- id
- firstname
- lastname
- password
- permissionLevel
The products will contain the following structure:
- id
- name
- description
- price
As for the coding standard, we are going to use TypeScript for this project. In the source file, you will be able to configure everything to start coding with TypeScript.
Let’s Code!
First of all, make sure you have the latest Node.js version installed. At the time of publication, the current version is 10.15.3, as per Nodejs.org.
Initializing the Project
Let’s start in a new folder that we can name node-graphql
. There, we can open a terminal or a Git CLI console and start the magic using the following command: npm init
.
Configuring our Dependencies and TypeScript
To speed up the process, replacing your package.json
with the following at our Git repository should contain all necessary dependencies:
{
"name": "node-graphql",
"version": "1.0.0",
"description": "",
"main": "dist/index.js",
"scripts": {
"tsc": "tsc",
"start": "npm run tsc && node ./build/app.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"@types/express": "^4.16.1",
"@types/express-graphql": "^0.6.2",
"@types/graphql": "^14.0.7",
"express": "^4.16.4",
"express-graphql": "^0.7.1",
"graphql": "^14.1.1",
"graphql-tools": "^4.0.4"
},
"devDependencies": {
"tslint": "^5.14.0",
"typescript": "^3.3.4000"
}
}
With the updated package.json
, just hit the terminal again and use: npm install
. It will install all dependencies needed to run this GraphQL API within Node.js and Express.
The next piece is to configure our TypeScript mode. We need a file called tsconfig.json
in our root folder with the following:
{
"compilerOptions": {
"target": "ES2016",
"module": "commonjs",
"outDir": "./build",
"strict": true,
"esModuleInterop": true
}
}
The logic of the code for this configuration will be present at the app folder. There we can create an app.ts
file and for basic testing add the following code there:
console.log('Hello Graphql Node API tutorial');
By our configuration, we now can run npm start
and wait for a build and be able to test that everything is working properly. In your terminal console, you should see our “Hello GraphQL Node API tutorial.” In the back scene, the configuration basically compiles the TypeScript code into pure JavaScript and then executes our build in the build
folder.
Now let’s configure a basic skeleton for our GraphQL API. For starting our project, we are going to add three basic imports:
- Express
- Express-graphql
- Graphql-tools
Let’s start putting it all together:
import express from 'express';
import graphqlHTTP from 'express-graphql';
import {makeExecutableSchema} from 'graphql-tools';
Now we should be able to start to code a bit. The next step is to deal with our app in Express and the basic GraphQL configuration like:
import express from 'express';
import graphqlHTTP from 'express-graphql';
import {makeExecutableSchema} from 'graphql-tools';
const app: express.Application = express();
const port = 3000;
let typeDefs: any = [`
type Query {
hello: String
}
type Mutation {
hello(message: String) : String
}
`];
let helloMessage: String = 'World!';
let resolvers = {
Query: {
hello: () => helloMessage
},
Mutation: {
hello: (_: any, helloData: any) => {
helloMessage = helloData.message;
return helloMessage;
}
}
};
app.use(
'/graphql',
graphqlHTTP({
schema: makeExecutableSchema({typeDefs, resolvers}),
graphiql: true
})
);
app.listen(port, () => console.log(`Node Graphql API listening on port ${port}!`));
What we are doing is:
- Enabling port 3000 for our Express server app.
- Defining which queries and mutations we want to use as a quick example.
- Defining how the queries and mutations are going to work.
OK, but what is going on for typeDefs and resolvers, as well as relation to queries and mutations?
- typeDefs - The definition of our schema of what we can expect from queries and mutations.
- Resolvers - Instead of the expectation of fields or required parameters, here we define the functions and behaviors of how should the queries and mutations would work.
- Queries - The “gets” that we want to read from the server.
- Mutations - Our requests that are going to affect any data that we have on our own server.
Now, let’s run npm start again to see what we have there. We would expect that the app will run with the following message: Node Graphql API listening on port 3000!
We can now try to query and test the GraphQL API on our own server via: http://localhost:3000/graphql
Great, now we can write our first very own query which was defined as “hello.”
Note that the way we defined it at the typeDefs
, the page can help us to build the query.
That’s great, but how can we change the value? Mutations!
Now, let’s see what happens when we change our in-memory value with a mutation:
Now we can do basic CRUD operations with our GraphQL Node.js API. Let’s advance with our code now.
Products
For products, we will use a module called products. As an effort to simplify this article, we are going to use an in-memory database just for demonstration. We will define a model and a service to manage products.
Our model will be based as follows:
export class Product {
private id: Number = 0;
private name: String = '';
private description: String = '';
private price: Number = 0;
constructor(productId: Number,
productName: String,
productDescription: String,
price: Number) {
this.id = productId;
this.name = productName;
this.description = productDescription;
this.price = price;
}
}
The service which will communicate with GraphQL will be defined as:
export class ProductsService {
public products: any = [];
configTypeDefs() {
let typeDefs = `
type Product {
name: String,
description: String,
id: Int,
price: Int
} `;
typeDefs += `
extend type Query {
products: [Product]
}
`;
typeDefs += `
extend type Mutation {
product(name:String, id:Int, description: String, price: Int): Product!
}`;
return typeDefs;
}
configResolvers(resolvers: any) {
resolvers.Query.products = () => {
return this.products;
};
resolvers.Mutation.product = (_: any, product: any) => {
this.products.push(product);
return product;
};
}
}
Users
For users, we will follow the same structure as the products module. We will have a model and a service for users. The model will be defined as:
export class User {
private id: Number = 0;
private firstName: String = '';
private lastName: String = '';
private email: String = '';
private password: String = '';
private permissionLevel: Number = 1;
constructor(id: Number,
firstName: String,
lastName: String,
email: String,
password: String,
permissionLevel: Number) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
this.password = password;
this.permissionLevel = permissionLevel;
}
}
Meanwhile, our service will be like:
const crypto = require('crypto');
export class UsersService {
public users: any = [];
configTypeDefs() {
let typeDefs = `
type User {
firstName: String,
lastName: String,
id: Int,
password: String,
permissionLevel: Int,
email: String
} `;
typeDefs += `
extend type Query {
users: [User]
}
`;
typeDefs += `
extend type Mutation {
user(firstName:String,
lastName: String,
password: String,
permissionLevel: Int,
email: String,
id:Int): User!
}`;
return typeDefs;
}
configResolvers(resolvers: any) {
resolvers.Query.users = () => {
return this.users;
};
resolvers.Mutation.user = (_: any, user: any) => {
let salt = crypto.randomBytes(16).toString('base64');
let hash = crypto.createHmac('sha512', salt).update(user.password).digest("base64");
user.password = hash;
this.users.push(user);
return user;
};
}
}
As a reminder, the source code is available for use from this link.
Now we can play and test our code. Let’s run npm start
. We will have the server running at port 3000. We can now access GraphQL for testing at http://localhost:3000/graphql.
Let’s try a mutation to add an item to our product list:
To test if it worked, we will now use a query for products, but receiving only id
, name
, and price
:
query{
products{
id,
name,
price
}
}
The response will be:
{
"data": {
"products": [
{
"id": 100,
"name": "My amazing product",
"price": 400
}
]
}
}
And that’s it; the product is working as expected. Now we can play and switch the fields around if we want to. You can try to add a description:
query{
products{
id,
name,
description,
price
}
}
Now we can have the descriptions of our products. Let’s try users now.
mutation{
user(id:200,
firstName:"Marcos",
lastName:"Silva",
password:"amaz1ingP4ss",
permissionLevel:9,
email:"marcos.henrique@toptal.com") {
id
}
}
And a query will be like:
query{
users{
id,
firstName,
lastName,
password,
email
}
}
With a response like:
{
"data": {
"users": [
{
"id": 200,
"firstName": "Marcos",
"lastName": "Silva",
"password": "kpj6Mq0tGChGbZ+BT9Nw6RMCLReZEPPyBCaUS3X23lZwCCp1Ogb94/oqJlya0xOBdgEbUwqRSuZRjZGhCzLdeQ==",
"email": "marcos.henrique@toptal.com"
}
]
}
}
And now our GraphQL skeleton is ready! There are tons of steps from here towards a useful, fully functional API, but the basic core is now set.
Summary and Final Thoughts
Even cutting edges to shorten up, the article is quite big with a lot of basic information regarding the development of a GraphQL Node.js API.
Let’s review what we’ve covered so far:
- Usage of Node.js with Express and GraphQL to build a GraphQL API;
- Basic GraphQL use;
- Basic usage of queries and mutations;
- Basic approach to creating modules for your project;
- Testing our GraphQL API;
To focus more on the development side of things, we avoided several important items which can briefly be summarized as follows:
- Validations for new items;
- Handling errors properly with a generic error service;
- Validating fields that a user can use at each request with a generic service;
- Add a JWT interceptor to secure the API;
- Handle password hash with a more effective approach;
- Add unit and integration tests;
Remember that we have the full source code at this Git link. Feel free to use, fork, open issues, make pull requests, and play with it! Please note that all standards and suggestions made in this article are not carved in stone.
This is just one of many approaches that can be used to start designing your own GraphQL API. Also, be sure to read and explore GraphQL in more detail, learning what it has to offer and how it can make your APIs even better.
Further Reading on the Toptal Blog:
Understanding the basics
Is GraphQL a language?
GraphQL is defined as a query language for client APIs and server-side runtime to execute those queries. That said, GraphQL is not exactly a language, but it has its own syntax and can be developed within several programming languages, such as Node.js.
What is the benefit of GraphQL?
GraphQL simplifies client usage in order to make requests and to filter what the client actually needs to consume, avoiding extra data being passed from the server side to the client side. It is a good alternative to REST, but can also be used with REST.
What exactly is Node.js?
Node.js is a cross-platform JavaScript runtime environment which allows us to develop back-end servers using JavaScript syntax. It can improve development speed when the software engineer is able to code with JavaScript, both back-end (node.js) and front-end (like Angular or React).
Is Node.js fast?
Node.js has proven to be very stable and fast for the past years. It is good for multi-tasking and works on the V8 engine that is used by Chrome.
Lecco, Province of Lecco, Italy
Member since February 25, 2017
About the author
Marcos is passionate about REST architecture, Agile development, and JavaScript. He has 8+ years of experience focusing on web apps.