DEV Community

Claradev32
Claradev32

Posted on

Building a Node.js API with Hapi.js and MongoDB

As our web applications scale, there is a need to reduce the development time by the use of a more reliable, and salable, tool, which gets the job done much faster.
In this tutorial, we will build a Book Store API with Hapi.js and MongoDB. We will set up MongoDB, Hapi.js and build a RESTful API.

Prerequisites

This tutorial will be a hands-on demonstration, you can find the source code on Gitbub. If you'd like to follow along, be sure you have the following:

  1. MongoDB Database - This tutorial uses MongoDB.
  2. Node.js - This tutorial uses Nodjs and NPM
  3. Postman - This tutorial uses Postman to test the API

What is Hap.js

Hapi.js is a Nodejs framework used to build powerful, scalable applications, with minimal overhead and full out-of-the-box functionality. Hapi.js was originally developed to handle Walmart’s Black Friday scale, hapi continues to be the proven choice for enterprise-grade backend needs.

Get started

To get started to create a folder for your project and access it from your terminal. Open the folder in Visual Studio Code or any other IDE you prefer.

mkdir BookApp //create a folder for the project
cd \BookApp // change directory to the app folder
Enter fullscreen mode Exit fullscreen mode

Then initialize NPM, which will create a package.json file in our app root directory where we store our dependencies.

npm init -y
Enter fullscreen mode Exit fullscreen mode

Next, we need to install some packages for our project.

npm install @hapi/Hapi mongoose dotenv morgan --save 
Enter fullscreen mode Exit fullscreen mode

Next, let's take a look at our project structure.

Project Structure

  • Controllers - is where we handle the application logic
  • Model - is where we handle our database collection ## Setting Up Hapi.js Server

We will start by creating a server.js and **file. Which is our application entry point.
In your project root directory create and **server.js
file, then import the Hapi package we installed in the previous section, create an instance of the Hapi server, specify the port you want the server to listen to, and host address*.*
Next, we will create the root route, of our application with a GET request and create a handler. For now, we will be sending a simple text to the client.
Finally, we start the Hapi.js server with the start method and display a message to the console.

Add this code to your server.js

const Hapi = require('@hapi/hapi');

const server = Hapi.server({
  port: 4000,
  host: '127.0.0.1'
});

server.route({
  method: 'GET',
  path: '/',
  handler: (req, h) => {

    return 'Hello I am Hapi!<';
  }
});

server.start();
console.log(`Server running on port ${server.info.uri}`);
Enter fullscreen mode Exit fullscreen mode

It's to start our server. run this command on your command line to start the server.

node server.js
Enter fullscreen mode Exit fullscreen mode

Next, open your web browser, navigate to localhost:4000. The server will respond with Hello I am Hapi!.

Creating a MongoDB Database

Now that you have learned how to create a Hapi server, let's go ahead and set up MongoDB for our project.
We will be using Mongoose to communicate with the MongoDB database.
Run this command to install Mongoose:

npm install mongoose
Enter fullscreen mode Exit fullscreen mode

Next, let’s connect MongoDB to our application using Mongoose. We will require mongoose, create a connection using the mongoose connect method and pass in our local server address to the server.
If the database is up, you should see “DB started” on the console.
Add this code to your server.js:

const mongoose = require("mongoose");
mongoose
 .connect("mongodb://localhost:27017/BookStore")
 .then(() => {
  console.log("db started!");
 })
 .catch((e) => {
  console.log(e);
 });
Enter fullscreen mode Exit fullscreen mode

Creating Book Schema

We now have our database up and running, let’s go ahead and create a book schema. Each book in our store will have a name, author, price, supplier, and createdAt.
Next, we define the type of data the documents should accept, then we validate the data from the users, to make sure they don’t submit empty records.
Add this code to model/BookModel:

const mongoose = require("mongoose");
const BookSchema = new mongoose.Schema({
 name: {
  type: String,
  required: [true, "Book price is required"],
 },
 author: {
  type: String,
  required: [true, "Authors name is required"],
 },
 price: { type: Number, required: [true, "Book price is required"] },
 ISBN: {
  type: String,
  required: [true, "Book ISBN is required"],
 },
 supplier :{
  type: String,
  required: [true, "Suppliers name is required"],
 },
 createdAt: {
  type: Date,
  default: Date.now(),
 },
});
module.exports = mongoose.model("Books", BookSchema);
Enter fullscreen mode Exit fullscreen mode

Creating Books

Now that we have defined our database schema. let’s go ahead and add a handler to add books to the store.
First, we require the Books model, then create and export our handler function.

Next, we create an object from the book model and add a record of the collection using the create method. The data from the form is stored in the payload as JSON, so we need to convert it to an object using the JSON parse method.
Lastly, we return the created document as a response to the users.

Add this code to controller/BookControllers.

exports.createBook = async (req, h) => {
 const data = await Books.create(JSON.parse(req.payload));
 return status;
};
Enter fullscreen mode Exit fullscreen mode

Now lets go ahead and create a route for this handler function.
add this code to your server.js

server.route({
 method: "GET",
 path: "/api/store",
 handler: controllers.getAllBooks,
});
Enter fullscreen mode Exit fullscreen mode

Getting All Books

Now that we can now add books to our database, let’s get the books stored in the database.
First, we get the books from the form, which is stored as JSON in the payload. Then we need to convert the data to an object since we store data as objects to our collection.

Add this code to controller/BookController:

exports.getAllBooks = async (req, h) => {
 const books = await Books.find();
 return books;
};
Enter fullscreen mode Exit fullscreen mode

Now let's go ahead and create a route for this handler function.
Add this code to server.js.

server.route({
 method: "POST",
 path: "/api/store",
 handler: controllers.createBook,
});
Enter fullscreen mode Exit fullscreen mode

Getting a Book

Let's go now get a book by its id.
First, we need the id of the Book selected, then we use object destructing to the id from the params object.
Next, we query the book collection to get a book by its id, using the findById method. Then now return the book to the client.

Add this code to controller/BookController:

exports.getBook = async(req, h) => {
 const {id} = req.params
 const book = await Books.findById({_id:id});
 return book;
};
Enter fullscreen mode Exit fullscreen mode

Next, let’s go ahead and create the getBook route with a patch request with an id parameter.

Add this code to server.js:

server.route({
 method: "GET",
 path: "/api/store/{id}",
 handler: controllers.getBook,
}
Enter fullscreen mode Exit fullscreen mode

Updating a Book

Now, let create a handler function to update the book in our collection.
First, we need to get the book id from the params object, also get the update data from the request payload.
Next, we create an object from the books model and use the findByIdAndUpdate method to update the book whose id is specified in the request parameters. Then convert the payload to an object and pass it as the new value of the document.

Next, we return the updated document with the new option set to true and send the document to the client.

Add this code to controller/BookController:

exports.updateBook = async (req, h) => {
 const { id } = req.params;
 const data = JSON.parse(req.payload);
 const modifiedBook = await Books.findByIdAndUpdate({ _id: id }, data, {
  new:true,
 });
 return modified book;
}
Enter fullscreen mode Exit fullscreen mode

Next, let’s go ahead and create the update route with a patch request and an id parameter.
Add this code to server.js:

server.route({
 method: "PATCH",
 path: "/api/store/{id}",
 handler: controllers.updateBook,
})
Enter fullscreen mode Exit fullscreen mode

Deleting a Book

Let's go ahead and create our delete handler.
First, we need to get the book id from the params object, then delete the book from the collection from the id.
Next, we return null to the client, since the record no longer exists.

Add this code to controller/BookController.js:

exports.deleteBook = async (req, h) => {
 const { id } = req.params;
 await Books.findByIdAndDelete({ _id: id });
 return "null";
};
Enter fullscreen mode Exit fullscreen mode

Next, let’s go ahead and create the delete route, which will listen to a delete request, then we pass an id as a parameter.

Add this code to server.js:

server.route({
method: "DELETE",
path: "/api/store/{id}",
handler: controllers.deleteBook,
})
Enter fullscreen mode Exit fullscreen mode




Testing our API

Now that we have implemented our RESTful API, let us go ahead and test them.
Open Postman, test the with these endpoints.

{
"name": "Advanced Javacript",
"price": 2000,
"ISBN" : "AD90976",
"supplier": "mark James",
"author": "james"
}

Conclusion

Throughout this tutorial, you've learned how to create a RESTful API using Hapi.js. You've also experienced setting up MongoDB and testing API using Postman.
Now, how would you use Hapi in your next project to create APIs?

Top comments (0)