Last updated on November 21, 2022
By reading this tutorial you can build RESTful APIs using Node, hapi.js, and Sequelize ORM. We gonna use the different HTTP methods during the REST API development, a quick introduction to each method, and route details along with the description of each endpoint you can find in the below table.
# | Route | Method | Description |
---|---|---|---|
1 | /todos | GET | Get all todos data |
2 | /todo/{id} | GET | Get a single todo data |
3 | /create | POST | Create a new todo record in the database |
4 | /update/{id} | PUT | Update a todo record |
5 | /delete/{id} | DELETE | Delete a todo record |
6 | /todos/search/{term} | GET | Search for todo, ex: PHP |
Each method has a purpose, isn’t it? Let me give an introduction to the app which you are going to build is a TODO application. You can add a to-do list, update, or delete todos and you can even search for todos.
Install sequelize-cli
The following npm command installs sequelize-cli
globally. It means you can access it from anywhere via the terminal.
npm install -g sequelize-cli
Project setup
Let’s create a folder for the project, for example, todo-app. And change the directory to the newly created directory(Ex: todo-app) and issue npm init –yes command to generate package.json in your project folder. Once it is done, then install the project npm dependencies called Hapi, mysql2, sequelize with the following command npm install hapi mysql2 sequelize
The command which we have executed in the preceding text
$ mkdir todo-app
$ cd todo-app
$ npm init --yes
$ npm install hapi mysql2 sequelize
And your final package.json
file should look something like the below shown
{
"name": "hapijs-reset-api",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "nodemon server.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"hapi": "^17.5.5",
"mysql2": "^1.6.1",
"sequelize": "^4.38.1"
}
}
Initializes sequelize
let the Sequelize CLI generate migrations, seeders, config, and models directories and config files.
$ sequelize init // Initializes project with sequelize cil
Ternamil output:
Sequelize CLI [Node: 8.11.1, CLI: 4.1.1, ORM: 4.39.0]
Created "config/config.json"
Successfully created models folder at "/Volumes/projects/workspace/todo-app/models".
Successfully created migrations folder at "/Volumes/projects/workspace/todo-app/migrations".
Successfully created seeders folder at "/Volumes/projects/workspace/todo-app/seeders".
After executing sequelize init
command, your folder structure should be similar to below shown
If you are a windows user correct the config file path in models/index.js
by changingvar config = require(__dirname + '/..\config\config.json')[env];
to var config = require(__dirname + '/../config/config.json')[env];
Database Configurations
Now config.json
file which is located at config\config.json
and updates your database details
{
"development": {
"username": "root",
"password": "",
"database": "arjunphp_node_rest",
"host": "127.0.0.1",
"dialect": "mysql"
},
"test": {
.......
.......
},
"production": {
.......
.......
}
}
Create Models and Migrations
Again we gonna use sequelize CLI command to generate model and migrations files.
sequelize model:create --name Todo --attributes title:string,description:string
Terminal output:
New model was created at /Volumes/projects/workspace/todo-app/models/todo.js .
New migration was created at /Volumes/projects/workspace/todo-app/migrations/20180928035740-Todo.js .
The above command generates a todo.js
file in the PROJECT_ROOT/models
folder as well as a -create-todo.js
migration file in the PROJECT_ROOT/migrations
folder. will be the date the model was generated.
PROJECT_ROOT/models/todo.js
Here is the generated model code, you can add or remove columns to it, make sure to update the migration file for your changes on this model.
'use strict';
module.exports = function(sequelize, DataTypes) {
var Todo = sequelize.define('Todo', {
title: DataTypes.STRING,
description: DataTypes.STRING
}, {
classMethods: {
associate: function(models) {
// associations can be defined here
}
}
});
return Todo;
};
PROJECT_ROOT/migrations/20180928035740-create-todo.js
Here is the generated migration code, you can add or remove columns to it, make sure to update the model file for your changes on this migration file.
'use strict';
module.exports = {
up: function(queryInterface, Sequelize) {
return queryInterface.createTable('Todos', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
title: {
type: Sequelize.STRING
},
description: {
type: Sequelize.STRING
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
down: function(queryInterface, Sequelize) {
return queryInterface.dropTable('Todos');
}
};
Run Migrations
You can create database tables by running migrations with:
sequelize db:migrate
That’s it, now you can check your database, and you should able to see new tables in your database.
Implementing the API calls with HapiJs
Create a file called server.js in the project root folder with below code:
const Hapi = require('hapi');
const server = Hapi.server({
port: 3000,
host: 'localhost'
});
const routes = require('./routes');
server.route(routes);
const init = async () => {
await server.start();
console.log(`Server running at: ${server.info.uri}`);
};
process.on('unhandledRejection', (err) => {
console.log(err);
process.exit(1);
});
init();
Now create a folder called routes
in the root of the project along with index.js
file and place the following code inside it.
const todos = require('./todos');
module.exports = [].concat(todos);
Now create a file called todos.js
as imported in routes/index.js
file and copy the following code to it.
const Models = require('../models/index')
const todosHandler = async (request, h) => {
try {
const todos = await Models.Todo.findAll({})
return { data: todos }
} catch (error) {
return h.response({ error: error.message }).code(400)
}
}
const createTodoHandler = async (request, h) => {
try {
const { title, description } = request.payload;
const todo = await Models.Todo.create({
title: title,
description: description
})
return {
data: todo,
message: 'New todo has been created.'
}
} catch (error) {
return h.response({
error: error.message
}).code(400)
}
}
const updateTodoHandler = async (request, h) => {
try {
const todo_id = request.params.id;
const { title, description } = request.payload;
const todo = await Models.Todo.update({
title: title,
description: description
}, {
where: {
id: todo_id
}
})
return {
message: 'Todo has been updated.'
}
} catch (error) {
return h.response({
error: error.message
}).code(400)
}
}
const deleteTodoHandler = async (request, h) => {
try {
const todo_id = request.params.id;
await Models.Todo.destroy({
where: {
id: todo_id
}
})
return { message: 'Todo has been deleted.' }
} catch (error) {
return h.response({
error: error.message
}).code(400)
}
}
module.exports = [
{ method: 'GET', path: '/todos', handler: todosHandler },
{ method: 'POST', path: '/todo', handler: createTodoHandler },
{ method: 'PUT', path: '/todo/{id}', handler: updateTodoHandler },
{ method: 'DELETE', path: '/todo/{id}', handler: deleteTodoHandler }
];
That’s it, hapi.js Rest server is ready, you can start the server with node server.js
and you can access it at http://localhost:3000
as mentioned in server.js
file.