Over a million developers have joined DZone.

Create a RESTful API With Node.js, Hapi, and Couchbase NoSQL

DZone's Guide to

Create a RESTful API With Node.js, Hapi, and Couchbase NoSQL

I feel like Hapi is much better designed than Express to create web services. In this article, I show how to create a simple RESTful API with Hapi and Couchbase Server.

· Database Zone ·
Free Resource

Download the Altoros NoSQL Performance Benchmark 2018. Compare top NoSQL solutions – Couchbase Server v5.5, MongoDB v3.6, and DataStax Enterprise v6 (Cassandra).

Developing Node.js applications with Express is no doubt a very popular option; however, it isn't the only option, and it may not even be the best option. I recently started looking into Hapi, which defines itself as being a framework for services — something that wasn't exactly a thing when Express came around.

Previously, I had written about creating a RESTful API with Node.js and Express, but this time around, we're going to explore doing the same with Hapi.

Before we get too invested in the code, we need to figure out what exactly we're going to be building. The goal here is to create a two endpoint application. One endpoint should allow us to create data in the database and the other should allow us to read from the database.

Create a new project directory somewhere on your computer and execute the following command from the command prompt within that directory:

npm init -y

The above command will create a new Node.js project by establishing a package.json file. The next step is to install each of the project dependencies.

Execute the following from the command line:

npm install couchbase hapi joi uuid --save

The above command will download the Couchbase Node.js SDK, the Hapi framework, Joi for data validation, and a package for generating UUID values to represent our NoSQL document keys.

Go ahead and create an app.js file within your project. This is where we will have all of our routing information and database logic. Open this app.js file and include the following JavaScript code:

const Hapi = require("hapi");
const Couchbase = require("couchbase");
const UUID = require("uuid");
const Joi = require("joi");

const server = new Hapi.Server();
const N1qlQuery = Couchbase.N1qlQuery;

const cluster = new Couchbase.Cluster("http://localhost");
const bucket = cluster.openBucket("default", "");

server.connection({ "host": "localhost", "port": 3000 });

    method: "GET",
    path: "/",
    handler: (request, response) => {
        return response("Hello World");

server.start(error => {
    if(error) {
        throw error;
    console.log("Listening at " + server.info.uri);

The above code will get us started. It imports each of our project dependencies, initializes Hapi for a specific host and port, and establishes a connection to Couchbase. We have also defined a single route to represent our root route.

For this example, Couchbase will be running locally and we'll be using a Bucket called default. For information on installing Couchbase, check out my tutorials for Mac, Linux, and Windows.

Now, we can worry about our two endpoints that interact with the database.

The first and probably simplest endpoint will be for returning a list of documents; in this case, people that had previously been created:

    method: "GET",
    path: "/people",
    handler: (request, response) => {
        var statement = "SELECT `" + bucket._name + "`.* FROM `" + bucket._name + "` WHERE type = 'person'";
        var query = N1qlQuery.fromString(statement);
        bucket.query(query, (error, result) => {
            if(error) {
                return response(error).code(500);
            return response(result);

Notice the handler method. In it, we construct an N1QL query that obtains all documents that have a type property that matches person. This means that we can have plenty of other document types that won't be picked up by our query.

If there is a problem with the query, we will return an error with a 500 response code; otherwise, we'll return the query results.

The next endpoint is where we make use of Joi for data validation. Check out the following JavaScript code:

    method: "POST",
    path: "/person",
    config: {
        validate: {
            payload: {
                firstname: Joi.string().required(),
                lastname: Joi.string().required(),
                type: Joi.any().forbidden().default("person"),
                timestamp: Joi.any().forbidden().default((new Date()).getTime())
    handler: (request, response) => {
        bucket.insert(UUID.v4(), request.payload, (error, result) => {
            if(error) {
                return response(error).code(500);
            return response(request.payload);

When a client tries to consume from this endpoint, validation happens as part of Hapi. In this validation process, we inspect the payload and make sure each of our properties meets the criteria. In this case, both firstname and lastname need to be present. It is forbidden for a type and timestamp property to exist in the request body. If they exist, and error will be returned. If they do not exist, a default value will be used.

If our validation passes, we can insert the data into Couchbase with a unique ID. The data will also be returned in the response.


You just saw how to create a very simple RESTful API with Hapi and Couchbase Server. I've been using Express since the beginning, but when it comes to Hapi, I feel like it was much better designed for creating web services. However, both will get the job done and if you'd like to see an Express alternative, check out this previous tutorial I wrote.

For more information on using Couchbase with Node.js, check out the Couchbase Developer Portal.

Download the whitepaper, Moving From Relational to NoSQL: How to Get Started. We’ll take you step by step through your first NoSQL project.

database ,tutorial ,couchbase ,nosql ,hapi ,restful api

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}