Skip to content

How to build APIs using hapi.js in Node.js

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.

#RouteMethodDescription
1/todosGETGet all todos data
2/todo/{id}GETGet a single todo data
3/createPOSTCreate a new todo record in the database
4/update/{id}PUTUpdate a todo record
5/delete/{id}DELETEDelete a todo record
6/todos/search/{term}GETSearch 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

hapi js rest tutorial | arjunphp.com

If you are a windows user correct the config file path in models/index.js by changing
var 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.

Create Models and Migrations ArjunPHP

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.

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments