Build a simple Node.js RESTful API
Tags: node, rest, api, mongodb
Published: 2021-05-09 11:39:57

## Table Of Contents
* [What is REST?](#chapter-1)
* [Prerequisites](#chapter-2)
* [Set up the workspace](#chapter-3)
* [Set up the database](#chapter-4)
* [Set up the routes](#chapter-5)
* [Set up the controller](#chapter-6)
* [Set up the server](#chapter-7)
* [Test the API](#chapter-8)
* [Conclusion](#chapter-9)
* [Final words](#chapter-10)

# What is REST? <a name="chapter-1"></a>
> REST is an acronym for Representational State Transfer and it is a software architectural style which uses a subset of HTTP
> RESTful APIs relies on HTTP verbs to perform four operations :
The GET (to read a resource), POST (to create and/or update a resource), and DELETE (to delete a resource)
> RESTful APIs are defined with the following aspects :
> * A base URI, such as http://api.example.com/;
> * Standard HTTP methods (e.g., GET, POST, PUT, and DELETE);
> * Media types, such as application/json.

In this tutorial, we will learn how to create a RESTful API using Node.js.

# Prerequisites <a name="chapter-2"></a>
In order to follow along with this tutorial you will need 
* A [Node.js](https://nodejs.org/en/download) environnement installed on your machine;
* A text editor program or IDE ([VS Code](https://code.visualstudio.com/download) for example);
* A mongoDB instance (here in this tutorial, we will be using the cloud database [MongoDB Atals](https://www.mongodb.com/cloud/atlas)).
* An API Client such as [Postman](https://www.postman.com/downloads/) to help us make HTTP requests and test our API server.

To avoid running into any compatibility issues, I will list the versions of programs and tools used in this tutorial :

| Tool                   | Version      | How to check        |
| ---------------------- | ------------ | ------------------- |
| Node.js                | v14.16.1     | `node -v`           |
| MongoDB Node.js driver | 3.6 or later |                     |
| express npm module     | ^4.17.1      | `npm list express`  |
| mongoose npm module    | ^6.0.10      | `npm list mongoose` |

# Set up the workspace <a name="chapter-3"></a>
## Start the project
In this tutorial, we will be creating a todo list application that will let us create, read, update and delete tasks.

Before we begin, make sure you have [Node.js](https://nodejs.org/en/download) installed, mongoDB Atlas instance working and [Postman](https://www.postman.com/downloads/) ready for the testing.

Now, open a terminal window (or CMD, on Windows) in a preferred location or use the following command to create a folder and set it as a workspace:

```
$ mkdir ./todo-list-api
```
```
$ cd ./todo-list-api
```

Now, it's time to start our application by typing the following command:

```
$ npm init -y
```
What it basically does is create a file named `package.json` that contains all the information about our project and its dependencies.

the `-y` parameter lets me skip filling informations about my project since I could modify these later in the `package.json` file.

## Create necessary folders and files

Now, let's create the file that will contain our server script, we'll be naming it `index.js` since that's the default name (other conventional names can be `app.js` or `server.js`).

In the command line, type the command that will create a new empty file:

```
$ touch ./index.js
```

Next, let's add some folders and files via the following commands:

Create 3 separate folders "models", "routes", and "controllers" using the command `$ mkdir controllers models routes`

Create the empty files "controller.js", "routes.js" and "model.js" inside their respective folders "controller", "routes", and "model" `$ touch ./controllers/controller.js ./models/model.js ./routes/routes.js`

# Set up the database <a name="chapter-4"></a>
Now that we have our server ready, let's set up a database.

1. Install mongoose module

mongoose will be used to manage our MongoDB Atlas instance.

```
$ npm install mongoose --save
```
2. Define a schema

Open the file "model.js" and type the following code and then save it.

```javascript
// model.js
const mongoose = require('mongoose');

const taskSchema = new mongoose.Schema({
  name: {
    type: String,
    required: 'Enter the name of the task'
  },
  date_created: {
    type: Date,
    default: Date.now
  },
  status: {
    type: [{
      type: String,
      enum: ['pending', 'ongoing', 'completed']
    }],
    default: ['pending']
  }
});

module.exports = mongoose.model('Tasks', taskSchema);
```
In the code above, we imported the mongoose module into our file and we created a model that defines the structure of our mongoDB collection.

# Set up the routes <a name="chapter-5"></a>
In Express, routing instructs the sever on how to respond to client request for a specific endpoint (URI) and a specific HTTP request method.

To do this, open the file "routes.js" and type the following code and then save it.
```javascript
// routes.js
module.exports = (app) => {
  const todoList = require('../controllers/controller.js');

  app.route('/tasks')
    .get(todoList.listTasks)
    .post(todoList.createTask);

  app.route('/tasks/:taskId')
    .get(todoList.readTask)
    .put(todoList.updateTask)
    .delete(todoList.deleteTask);
};
```
In the code above, we defined two basic routes : "/tasks" and "/tasks/:taskId" with different methods; "/tasks" has the methods "GET" and "POST", while "/tasks/:taskId" has "GET", "PUT" and "DELETE".
As you can see, we also required the controller so each of the routes methods can call its respective handler function.

# Set up the controller
open the file "controller.js" and type the following code and then save it.

```javascript
// controller.js
const mongoose = require('mongoose');
const task = mongoose.model('Tasks');

exports.listTasks = (req, res) => {
  task.find({}, (err, task) => {
    if (err)
      res.send(err);
    res.json(task);
  });
};

exports.createTask = (req, res) => {
  const new_task = new task(req.body);
  new_task.save((err, task) => {
    if (err)
      res.send(err);
    res.json(task);
  });
};

exports.readTask = (req, res) => {
  task.findById(req.params.taskId, (err, task) => {
    if (err)
      res.send(err);
    res.json(task);
  });
};

exports.updateTask = (req, res) => {
  task.findOneAndUpdate({_id: req.params.taskId}, req.body, {new: true}, (err, task) => {
    if (err)
      res.send(err);
    res.json(task);
  });
};

exports.deleteTask = (req, res) => {
  task.remove({
    _id: req.params.taskId
  }, (err, task) => {
    if (err)
      res.send(err);
    res.json({ message: 'Task deleted' });
  });
};
```
In the code above, we defined 5 different functions for different actions:
* `listTasks` lists our tasks;
* `createTask` creates a new task;
* `readTask` reads the content of a task;
* `updateTask` updates the content of a task;
* `deleteTask` deletes a task.

Each of these functions is exported in order to be used in our routes.

Note that each of these functions uses different mongoose methods such as find, findById, save, findOneAndUpdate and deleteOne.

# Set up the server <a name="chapter-6"></a>

In this section, we will be connecting our `controller.js`, database, the created models, body parser and the routes together and at the end, we will run our server and test it.

1. Install express module

Express will be used to create the server

```
$ npm install express --save
```
2. Start the server <a name="chapter-7"></a>

Open the file "index.js" and follow the steps.

Essentially, what we will be doing is
* Connect our database by adding a url to the mongoose instance connection (you can learn how to set up one by following [this article](https://docs.atlas.mongodb.com/tutorial/connect-to-your-cluster/#connect-to-your-atlas-cluster));
* Load the created model - task;
* Register our created routes in the server.

Now, type the following code inside the file `index.js` and save it.
Note : Don't forget to replace the string in `connectionUrl` variable with your Atlas connection string.

```javascript
// index.js
const express = require('express');
const app = express();
const port = process.env.PORT || 3000;
const mongoose = require('mongoose');
const task = require('./models/model.js');

app.use(express.json());
app.use(express.urlencoded({ extended: true }));

// mongoose instance connection url connection
mongoose.Promise = global.Promise;
// Replace the following with your Atlas connection string                                                                                                                                        
const connectionUrl = "mongodb+srv://<username>:<password>@<clusterName>.mongodb.net/<databaseName>?retryWrites=true&w=majority";
mongoose.connect(connectionUrl, { 
    useNewUrlParser: true,
    useUnifiedTopology: true 
  }); 

//import routes
const routes = require('./routes/routes.js'); 

//register the route
routes(app);

app.listen(port, ()=> {
  console.log(`RESTful API server running on ${port}`);
});
```
Now, back to the terminal and type `$ node ./index.js` and if everything is fine, you'll see the message **"RESTful API server running on 3000"** printed to the console.

# Test the API <a name="chapter-8"></a>

Now that everything is connected, let’s test some of our routes with the the registered methods.

Launch Postman or use the [web-based version](https://web.postman.co/home) (you'll need to set up an account, it's free).

In Postman, we will test our routes by making requests to their respective endpoints

Since there are no tasks nor tasklists in our database yet, get requests will return an empty array (`[]`) from the server. So the first thing we can do is create a task.

## Create a task
In order to create a new task, let's make a `POST` request to the following `http://localhost:3000/tasks`

![Create task in Postman](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t8eejpf1rv3so8yh6pk6.png)
 
if you can't use Postman for some reason, you can always use the command line tool "curl".

```
$ curl --data-urlencode 'name=Do homework' http://localhost:3000/tasks
```
## Delete a task
Now let's try to delete the task we have just created, in order to do that, let's make a `DELETE` request to the following `http://localhost:3000/tasks/<taskId>`
Note that we have to replace the `:taskId` placeholder with the task identified `_id` we received from the last request. 

![Delete task in Postman](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e2rndv010xtp6bxq0dbp.png)

Again, if you can't use Postman, use the command line tool "curl".
```
$ curl -X DELETE "http://localhost/<taskId>"
```

# Conclusion <a name="chapter-9"></a>
Congrats! you made a functioning RESTful API.
You may find the full code for this tutorial in this [Github Repository](https://github.com/youssefallalix/todo-list-api).

# Final words <a name="chapter-10"></a>
Don't hesitate to leave any questions you may have for me in the comments. I'll be pleased to reply and subscribe for more interesting content like this one.