Over the years, NodeJS and its Express Framework, have made a name for themselves in the web development space.
At the same time, the REST API has established itself as a reference for data exchange between servers and clients. Hence, the Node JS REST API stack has become a suitable choice in the design of web services.
So, in this blog article, I will show you how to build a REST API with Nodejs and Express.
First, what is a REST API?
A REST API is a way of accessing web services in a simple and flexible way without having any processing. REST stands for Representational State Transfer, and it is an architectural style that defines how applications can communicate over the internet using HTTP methods.
Some of the benefits of using REST API are:
Related: Post man for beginners
- It is easy to use and understand, as it follows the standard HTTP methods and conventions.
- It is lightweight and efficient, as it uses less bandwidth and resources than other web services like SOAP.
- It is scalable and adaptable, as it can handle different types of data formats and support multiple platforms.
Some of the key concepts of REST API are:
- Resource: A resource is anything that can be identified by a URI (Uniform Resource Identifier), such as a user, a product, a document, etc. A resource can have different representations, such as JSON, XML, HTML, etc.
- URI: A URI is a string that uniquely identifies a resource on the web. A URI consists of a scheme, a host, a path, and optionally a query and a fragment. For example,
https://example.com/users/123?name=John#profile
is a URI that identifies a user resource with the ID 123, the name John, and the profile section. - HTTP Method: A HTTP method is a verb that indicates the action to be performed on a resource. The most common HTTP methods are GET, POST, PUT, PATCH, and DELETE, which correspond to the CRUD (Create, Read, Update, Delete) operations. For example, GET
/users/123
means to retrieve the user resource with the ID 123, while POST/users
means to create a new user resource. - HTTP Status Code: A HTTP status code is a three-digit number that indicates the result of a request. The status codes are grouped into five categories: 1xx (informational), 2xx (success), 3xx (redirection), 4xx (client error), and 5xx (server error). For example, 200 OK means that the request was successful, while 404 Not Found means that the resource was not found.
Now that we’ve had a brief overview of what a REST API is and how it works…
Why use Node JS to build a REST API?
Many developers use Node JS to build their APIs for the following reasons:
Related: what can Nodejs do?
- It’s non-blocking processing of requests.
NodeJS only has one thread. That is, there is only one “engine” available to process incoming requests to the server. However, Node JS has the ability to outsource “blocking” functions to the callback queue, allowing it to come back to process. - Its performance and scalability
NodeJS, being able to process several requests in a non-blocking way, coupled with its modularity, its performance within the framework of an API is remarkable. The design of a Node JS API makes it possible to multiply the instances of the modules which are under pressure from incoming calls. - The JavaScript ecosystem and open-source packages available
NPM is the registry (which could be translated as a library) that hosts all the libraries. Whatever your need, there is surely a library to help you code your functionality. This richness of the ecosystem makes the development of a Node JS API faster.
Building a Node API with Express
In this guide, we’ll create a very simple REST API in order for you to understand each element that makes it up.
Note that we’re not going to run some tests and skip some best practices that aren’t within the scope of this guide.
Create an Express Server
Your Node JS API is primarily a web server listening to incoming HTTP requests. To start this web server, we will use the Express framework.
Start the Node JS API project
- Create your future API directory and navigate inside
- Enter the command
npm init
and answer the questions - Create an index.js
You will now have a package.json file in your directory, which will contain various project information and which will contain the dependencies that will be installed there.
Adding Express to our Node JS API
Now go back to your terminal and type the following command:
npm install express
The purpose of this command is to download from the NPM registry and then install the express library as well as all the libraries that express needs to run in your working directory, in the node modules folder.
NPM will equally add it to your package.json file in the dependencies.
ℹ️ In some online tutorials, you will find the option --save
or -s
after the npm install
command. Be aware that before version 5.0 of NPM, you had to pass this option to find the dependency added in the package.json
. However, since version 5.0, as soon as you place the npm install
command, the library is by default added to the package.json. It is no longer necessary to pass the option -s
or --save
❓ Why do we need to add the dependency in package.json?
ℹ️ For a Node JS API project or any other Node project to be taken over by another developer or deployed to a remote server, the package.json
file MUST reference all the libraries the application needs to work well. You will not upload your whole application with the node_modules
directory but just your code and the package.json
. The server will be in charge of making a npm install
to retrieve all dependencies.
Creating the Express server in our index.js file
Now that Express is available in our project, we can create the server. Let’s start by integrating the express library into our index.js file:
const express = require('express');
const app = express();
The require('express')
is used to import the express library and its functions into our code. The constant app
is the instantiation of an Express object, which will contain our server and the methods we will need to make it work.
❓ You may have seen the syntax import express from 'express'
? This import syntax is based on ES6. This syntax is widely used in frontend development because it allows you to import only the methods that are used and to reduce the size of the JavaScript file to be loaded by the browser. In the case of a Node JS API, the code is executed on a server. The gain is not as important as in the front-end. Switching to an import syntax will require more configuration work than a syntax using require
For the moment, your server is prepared but not launched yet. If you type in localhost:8080
from your browser, you should get an error.
For our server to be able to listen, we must now use the method listen
provided in app
and specify a port. Most often in development, we use 8080, 3000, or 8000.
It doesn’t matter which port you use as long as you don’t have other applications running locally on that same port.
app.listen(8080, () => {
console.log('Server Listening)
});
By issuing the command node index.js
in your terminal, it will show that your server is listening. This means that everything is working fine.
If there is an error, you will see an error message on your terminal.
Also, if you go to your browser at localhost:8080
(or the other port you chose), you will notice your server responds to your browser, but having no route configured for the moment, it returns this error Cannot GET /
but it is indeed functional.
Defining a resource and its routes
Now that your server is up and running, it’s time to define the heart of your API: its resources.
Defining the resources of our Node JS API
For our example, we will use the case of a company operating long-term car parks and taking reservations from its customers.
We will need the following features:
- Create a car park
- List all car parks
- Retrieve details of a specific car park
- Delete a parking
- Make reservations for a space in a car park
- List all reservations
- View details of a specific booking
- Delete a reservation
These operations are more commonly called CRUD, for CREATE, READ, UPDATE, DELETE.
In our example, our Node JS API has two resources: Parking and Reservation.
Creation of routes
The REST API standard dictates that our routes be centered around our resources and that the HTTP method used reflects the intent of the action.
In our case we will need the following routes:
- GET /parking
- GET /parking/:id
- POST /parking
- PUT /parking/:id
- DELETE /parking/:id
Reservations being a sub-resource of the parking resource, we will have to create the following routes:
- GET /parking/:id/reservations
- GET /parking/:id/reservations/:idReservation
- POST /parking/:id/reservations
- PUT /parking/:id/reservations/:idReservation
- DELETE /parking/:id/reservations/:idReservation
For our Node JS API to work, we need sample data.
The purpose of this guide is to help you understand how an API works. We are not going to connect a real database in this guide. We will instead use a JSON file containing sample data to manipulate our API.
To download this file, click here then place it at the root of your working directory.
Let’s start by defining the GET /parking route.
The purpose of this route is to retrieve all the parking lots in our data. Let’s modify our index.js :
const express = require('express');
const app = express();
app.get('/parking', (req, res) => {
res.send("List of parking lots")
});
app.listen(8080, () => {
console.log("Server Listening")
});
Express’s .get
method allows you to define a GET route.
It takes as its first parameter a String which defines the route to listen to and a callback, which is the function to execute if this route is called.
This callback takes the object req
, which is all the data provided by the request, and the object res
, provided by express, which contains the methods that’ll respond to the request that just arrived.
In this code, when a GET request arrives on the URL localhost:8080/parking
, the server is instructed to send the String “List of parking lots”.
Shut down your node server if it’s still running (with the ctrl+c command in the terminal) and run the command again node index.js
in order to take the changes into account.
ℹ️ For every modification in the code of your Node JS API, you will have to restart the server so that they are taken into account. Nevertheless, you may use Nodemon which allows you to automatically restart your node server each time you save your file. To install it, enter the command npm install nodemon -g
then when you first launch your server, use the command nodemon
instead of node index.js
Now that our route is working and is able to receive the incoming request, we will be able to return the parking data instead of just having a string:
const express = require('express');
const app = express();
const parking = require('./parking.json');
app.get('/parking', (req,res) => {
res.status(200).json(parking)
});
app.listen(8080, () => {
console.log("Server Listening")
});
We replaced the method send
by the method JSON.
Indeed our REST API will return a JSON file to the client and not text or an HTML file.
We also added status 200, which is the HTTP response code telling the client that their request was completed successfully.
Our GET /Parking route is now complete. We now need to set up the following routes using JavaScript methods to meet our needs.
The GET /parking/:id route is as follows.
We need to retrieve the route id from the URL to display only the JSON of this parking lot in the response. This id can be found in the params, in the object req
, sent by the browser.
Let’s go back to our index.js :
const express = require('express')
const app = express()
const parkings = require('./parking.json')
app.get('/parking', (req, res) => {
res.status(200).json(parking)
})
app.get('/parking/:id', (req,res) => {
const id = parseInt(req.params.id)
const parking = parking.find(parking => parking.id === id)
res.status(200).json(parking)
})
app.listen(8080, () => {
console.log("Server Listening")
})
The value of req.params.id contains what is sent in the URL, as a String. As the id of each car park is in the form of a Number, it is necessary to transform the params from String to Number. Then, you have to search in the parking lots to find the one with the id corresponding to the one passed in the URL.
Let’s go to the POST /parking route in order to be able to create a new parking lot.
To create a new car park via your Node JS API, you will have to send to the server the data relating to this new element, such as its name, its type, etc.
When it comes to sending data, you must use a POST request
This middleware will place itself between the arrival of the request and our routes and execute its code, making it possible to access the body.
const express = require('express')
const app = express()
const parking = require('./parking.json')
// Middleware
app.use(express.json())
app.get('/parking', (req, res) => {
res.status(200).json(parking)
})
app.get('/parking/:id', (req,res) => {
const id = parseInt(req.params.id)
const parking = parking.find(parking => parking.id === id)
res.status(200).json(parking)
})
app.listen(8080, () => {
console.log("Server Listening")
})
Now, we just have to add the POST route and test our new route:
const express = require('express')
const app = express()
const parking = require('./parking.json')
// Middleware
app.use(express.json())
app.get('/parkings', (req, res) => {
res.status(200).json(parking)
})
app.get('/parking/:id', (req, res) => {
const id = parseInt(req.params.id)
const parking = parking.find(parking => parking.id === id)
res.status(200).json(parking)
})
app.post('/parkings', (req, res) => {
parking.push(req.body)
res.status(200).json(parking)
})
app.listen(8080, () => {
console.log("Server Listening")
})
To test our POST route, we are going to use the Postman tool which allows us to easily manipulate APIs.
Our POST request on the URL localhost:8080/parkings
contains in its body a JSON object containing the id, name, type, and city of our new parking lot.
In a real case of Node JS API, your database would have generated the id. In our case, we are going to pass it by hand for simplicity.
Let’s go to the PUT route /parkings/:id to be able to modify a parking lot.
app.put('/parking/:id', (req,res) => {
const id = parseInt(req.params.id)
let parking = parking.find(parking => parking.id === id)
parking.name =req.body.name,
parking.city =req.body.city,
parking.type =req.body.type,
res.status(200).json(parking)
})
Here is the code corresponding to the PUT route. I’ll let you guess where to put it in the index.js file.
We are now left with the route ` DELETE /parkings`
app.delete('/parkings/:id', (req,res) => {
const id = parseInt(req.params.id)
let parking = parkings.find(parking => parking.id === id)
parkings.splice(parkings.indexOf(parking), 1)
res.status(200).json(parkings)
})
Your Node JS API is now able to manage the Parking resource. To implement the Reservation sub-resource, the logic must be replicated.
Your turn to play!
To prepare the data for your Node JS API, here is the reservations.json to place at the root of your project.
For the rest of your Node JS API, it’s your turn to play. This time, the Reservation resources depend on the Parking resource. For example, the GET route /parkings/1/reservations
will retrieve all the reservations for car park 1.