Welcome back, This is the second part of a tutorial on how to build a RESTful Api with node.js and express.js. So far we have built an Api to create, read, update and delete. In these tutorials we’ll be looking at improving our code. We’ll be looking at two things basically, First will be express router Middleware, secondly, we’ll refactor our callback function into a separate file of its own so as to separate concerns and make our code clean.

Middleware

What is a middleware? from the express doc Middleware functions are functions that have access to the request object (req), the response object (res), and the next middleware function in the application’s request-response cycle. The next middleware function is commonly denoted by a variable named next.

Router middleware

From the terminal navigate to root of your app.

$ cd todo

Create a new directory called routes.

$ mkdir routes

in your routes folder create a new file called index.js.

$ cd routes
$ touch index.js

Now in index.js write the following code

import express from 'express';
import db from '../db/db';

const router = express.Router();

We import express and then create a route handler with express.Router()

In your app.js move the code for your endpoint and paste it in index.js inside of the routes folder. instead of app.get, user router.get and do the same for the remaining endpoints.You should have something like this when you are done.

router.get('/api/v1/todos', (req, res) => {
res.status(200).send({
success: 'true',
message: 'todos retrieved successfully',
todos: db,
});
});

router.get('/api/v1/todos/:id', (req, res) => {
const id = parseInt(req.params.id, 10);
db.map((todo) => {
if (todo.id === id) {
return res.status(200).send({
success: 'true',
message: 'todo retrieved successfully',
todo,
});
}
});
return res.status(404).send({
success: 'false',
message: 'todo does not exist',
});
});

router.post('/api/v1/todos', (req, res) => {
if (!req.body.title) {
return res.status(400).send({
success: 'false',
message: 'title is required',
});
} else if (!req.body.description) {
return res.status(400).send({
success: 'false',
message: 'description is required',
});
}
const todo = {
id: db.length + 1,
title: req.body.title,
description: req.body.description,
};
db.push(todo);
return res.status(201).send({
success: 'true',
message: 'todo added successfully',
todo,
});
});


router.put('/api/v1/todos/:id', (req, res) => {
const id = parseInt(req.params.id, 10);
let todoFound;
let itemIndex;
db.map((todo, index) => {
if (todo.id === id) {
todoFound = todo;
itemIndex = index;
}
});

if (!todoFound) {
return res.status(404).send({
success: 'false',
message: 'todo not found',
});
}

if (!req.body.title) {
return res.status(400).send({
success: 'false',
message: 'title is required',
});
} else if (!req.body.description) {
return res.status(400).send({
success: 'false',
message: 'description is required',
});
}

const newTodo = {
id: todoFound.id,
title: req.body.title || todoFound.title,
description: req.body.description || todoFound.description,
};

db.splice(itemIndex, 1, newTodo);

return res.status(201).send({
success: 'true',
message: 'todo added successfully',
newTodo,
});
});

router.delete('/api/v1/todos/:id', (req, res) => {
const id = parseInt(req.params.id, 10);
let todoFound;
let itemIndex;
db.map((todo, index) => {
if (todo.id === id) {
todoFound = todo;
itemIndex = index;
}
});

if (!todoFound) {
return res.status(404).send({
success: 'false',
message: 'todo not found',
});
}
db.splice(itemIndex, 1);

return res.status(200).send({
success: 'true',
message: 'Todo deleted successfuly',
});
});

To make use of this routes in our app we need to import it into app.js, to import it into app.js we need to export it from index.js inside of the route folder, let’s do that.

in index.js file, type in the following code to export router

message: 'Todo deleted successfuly',
});
});
export default router;

Now in app.js, import the router

import router from './routes/index.js';

the newly imported router is a middleware, to make use of middleware in express you use app.use(middleware)

app.use(bodyParser.urlencoded({ extended: false }));
app.use(router);

Now let’s run our code to be sure that we’ve broken nothing.

Refactor The Callback Functions

from the root of your application create a new folder called todosController

$ mkdir todosControllers

in todosControllers folder create a file called todos

$ cd todosControllers
$ touch todos.js

Now inside todos.js we are going to create a class, this class is going to hold all our callback functions as its methods, whenever we need to make use of any of the methods we’ll create an instance of the class and get the method we need. let’s create this class.

/* eslint-disable class-methods-use-this */
import db from '../db/db';

class TodosController {
getAllTodos(req, res) {
return res.status(200).send({
success: 'true',
message: 'todos retrieved successfully',
todos: db,
});
}

getTodo(req, res) {
const id = parseInt(req.params.id, 10);
db.map((todo) => {
if (todo.id === id) {
return res.status(200).send({
success: 'true',
message: 'todo retrieved successfully',
todo,
});
}
});
return res.status(404).send({
success: 'false',
message: 'todo does not exist',
});
}

createTodo(req, res) {
if (!req.body.title) {
return res.status(400).send({
success: 'false',
message: 'title is required',
});
} else if (!req.body.description) {
return res.status(400).send({
success: 'false',
message: 'description is required',
});
}
const todo = {
id: db.length + 1,
title: req.body.title,
description: req.body.description,
};
db.push(todo);
return res.status(201).send({
success: 'true',
message: 'todo added successfully',
todo,
});
}

updateTodo(req, res) {
const id = parseInt(req.params.id, 10);
let todoFound;
let itemIndex;
db.map((todo, index) => {
if (todo.id === id) {
todoFound = todo;
itemIndex = index;
}
});

if (!todoFound) {
return res.status(404).send({
success: 'false',
message: 'todo not found',
});
}

if (!req.body.title) {
return res.status(400).send({
success: 'false',
message: 'title is required',
});
} else if (!req.body.description) {
return res.status(400).send({
success: 'false',
message: 'description is required',
});
}

const newTodo = {
id: todoFound.id,
title: req.body.title || todoFound.title,
description: req.body.description || todoFound.description,
};

db.splice(itemIndex, 1, newTodo);

return res.status(201).send({
success: 'true',
message: 'todo added successfully',
newTodo,
});
}

deleteTodo(req, res) {
const id = parseInt(req.params.id, 10);
let todoFound;
let itemIndex;
db.map((todo, index) => {
if (todo.id === id) {
todoFound = todo;
itemIndex = index;
}
});

if (!todoFound) {
return res.status(404).send({
success: 'false',
message: 'todo not found',
});
}
db.splice(itemIndex, 1);

return res.status(200).send({
success: 'true',
message: 'Todo deleted successfuly',
});
}
}

const todoController = new TodosController();
export default todoController;

To use the methods in this class we created an instance of the class and export it. now in our routes files(routes/index.js) we will import the class instance we just created and use its methods as callbacks instead of the anonymous function we were using before, let’s replace all of this functions with a method that does exactly the same thing they do.

First we import the object, go to index.js in routes folder and do this.

import todoController from '../todosControllers/todos';

Now replace the function with their equivalent method of the todoController object. our index.js file should look like this.

import express from 'express';
import TodoController from '../todosController/todos';

const router = express.Router();

router.get('/api/v1/todos', TodoController.getAllTodos);
router.get('/api/v1/todos/:id', TodoController.getTodo);
router.post('/api/v1/todos', TodoController.createTodo);
router.put('/api/v1/todos/:id', TodoController.updateTodo);
router.delete('/api/v1/todos/:id', TodoController.deleteTodo);

export default router;

Now let’s test our app to see if it still works.

That brings us to the end of the second part of this tutorial, Thanks for your time and I do hope you’ve learnt something.

The link to the third part of this series is here

--

--