Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Using PouchDB and Couchbase NoSQL in Your Node.js Web App

DZone's Guide to

Using PouchDB and Couchbase NoSQL in Your Node.js Web App

Bring some NoSQL goodness to your server-side and browser-based apps using a combination of PouchDB, Couchbase, and, of course, Node.js.

· Database Zone
Free Resource

Traditional relational databases weren’t designed for today’s customers. Learn about the world’s first NoSQL Engagement Database purpose-built for the new era of customer experience.

One of my preferred technologies for developing web applications is Node.js. I do a lot of JavaScript development, so it is another piece to fit in my development puzzle. Not too long ago I wrote a guide for using Couchbase Mobile and the Couchbase Node.js SDK in the same stack. In that article, I had mentioned there are several different ways to accomplish this task. I figured I would elaborate on another way to get the job done, this time using PouchDB.

PouchDB is a JavaScript database that works in combination with Couchbase Sync Gateway and Couchbase Server. Being that it is JavaScript, you can use it in your server-side and browser-based applications.

The Requirements

Since this is a JavaScript application, there won't be many software dependencies. The few that exist are as follows:

This is a Node.js application, but the Node Package Manager (NPM) is what will do most of the heavy lifting when it comes to preparing our project. It will obtain PouchDB and the remaining dependencies. We'll be using the Couchbase Sync Gateway in-memory database because this is only an example application. In production, you'll want to hook Sync Gateway to Couchbase Server for persisted storage.

Configuring Couchbase Sync Gateway for Data Synchronization

Sync Gateway will handle all of our remote data before and after it hits Couchbase Server. It is our middleman service that will orchestrate the data between platforms, devices, etc. It is not a requirement when building Node.js applications that work with Couchbase Server. We're using it because we wish to support mobile synchronization as well, even though it won't be demonstrated in this example.

With Couchbase Sync Gateway downloaded and installed, we need to establish a configuration to load at runtime. Create a file called sync-gateway-config.json and include the following:

{
    "log":["CRUD+", "REST+", "Changes+", "Attach+"],
    "databases": {
        "example": {
            "server":"walrus:",
            "sync":`
                function (doc) {
                    channel (doc.channels);
                }
            `,
            "users": {
                "GUEST": {
                    "disabled": false,
                    "admin_channels": ["*"]
                }
            }
        }
    },
    "CORS": {
        "Origin": ["http://localhost:3000"],
        "LoginOrigin": ["http://localhost:3000"],
        "Headers": ["Content-Type"],
        "MaxAge": 17280000
    }
}


In the above very basic configuration file, we establish a database called example that uses the in-memory Sync Gateway storage option. There are no specific read or write permissions in this configuration which means all the data will exist in the same channel.

Because we are running Sync Gateway and our soon to be created Node.js example on the same machine, but different ports, we have to allow cross-origin resource sharing (CORS). If we don't then we'll end up with JavaScript related errors. In the above configuration, we're saying that we want to allow communication from http://localhost:3000, which is our Node.js application.

At this point Sync Gateway can be run. In a production environment, the in-memory walrus solution can be replaced with the hostname of a particular Couchbase Server cluster.

Developing the Node.js Web Application

To make things easy to understand, we're going to create a fresh Node.js application and work our way up. This can be done using the Node Package Manager.

From the Command Prompt or Terminal, execute the following:

npm init --y


The above command will create a package.json file which will maintain all of our project dependencies. With the package.json file in place, let's obtain a few dependencies:

npm install express body-parser pouchdb --save


The above command will install Express Framework, a package necessary for handling body data in requests, and PouchDB for managing our application data.

Before we can begin writing code, we need to create a file called app.js which will contain all of our application logic.

Bootstrapping the RESTful API

With the app.js file created, open it and include the following JavaScript code:

var Express = require("express");
var BodyParser = require("body-parser");
var PouchDB = require("pouchdb");

var app = Express();

app.use(BodyParser.json());
app.use(BodyParser.urlencoded({ extended: true }));

var database = new PouchDB("http://192.168.57.1:4984/example");

app.get("/people", function(req, res) { });

app.get("/people/:id", function(req, res) { });

app.post("/people", function(req, res) { });

app.delete("/people", function(req, res) { });

var server = app.listen(3000, function() {
    database.info().then(function(info) {
        console.log(info);
        console.log("Listening on port %s...", server.address().port);
    });
});


So what is happening in the above code? First of all, we're importing the dependencies that were previously install and we are initializing them.

Because this is a server-side application we have two options when it comes to using PouchDB. We could create a local database on our application server that synchronizes with Sync Gateway or we can connect to the Sync Gateway instance directly.

var database = new PouchDB("http://192.168.57.1:4984/example");


The above indicates that we are going to connect to our locally running Sync Gateway server directly. You might choose the sync option if you want to take a different approach at load balancing.

app.get("/people", function(req, res) { });
app.get("/people/:id", function(req, res) { });
app.post("/people", function(req, res) { });
app.delete("/people", function(req, res) { });


We'll be building a RESTful API that uses CRUD, but for now, it makes sense to just define each of the endpoints we wish to use in Express Framework.

Finally, we define how we want to serve the application:

var server = app.listen(3000, function() {
    database.info().then(function(info) {
        console.log(info);
        console.log("Listening on port %s...", server.address().port);
    });
});


We are going to serve the application at http://localhost:3000 and when the server boots we will print out information regarding PouchDB. It will help give us an idea about the connection and the data that exists.

Including the PouchDB Data Manipulation Logic

With the application bootstrapped, we can start applying application logic to each of the endpoint methods. Starting with the list endpoint, we have the following:

app.get("/people", function(req, res) {
    database.allDocs({include_docs: true}).then(function(result) {
        res.send(result.rows.map(function(item) {
            return item.doc;
        }));
    }, function(error) {
        res.status(400).send(error);
    });
});


When the endpoint is hit, we will query for all documents and include the document properties in the results. To skip over information that might not be useful to us we can map the response before returning it. Otherwise, we can return an error.

Instead of listing all documents we might want to obtain a single document.

app.get("/people/:id", function(req, res) {
    if(!req.params.id) {
        return res.status(400).send({"status": "error", "message": "An `id` is required"});
    }
    database.get(req.params.id).then(function(result) {
        res.send(result);
    }, function(error) {
        res.status(400).send(error);
    });
});


In the above scenario we expect a document id to be included in the request. If the id exists we will try to obtain a document and return it to the requestor, otherwise we'll return an error.

How about creating new documents?

To create documents inside Couchbase, we would do something like the following:

app.post("/people", function(req, res) {
    if(!req.body.firstname) {
        return res.status(400).send({"status": "error", "message": "A `firstname` is required"});
    } else if(!req.body.lastname) {
        return res.status(400).send({"status": "error", "message": "A `lastname` is required"});
    }
    database.post(req.body).then(function(result) {
        res.send(result);
    }, function(error) {
        res.status(400).send(error);
    });
});


In the above code, we are expecting a firstname and a lastname to exist. If this is true, we will create the document using the entire post body and return the response. We don't have to use the entire post body, but in this example we are. Just note that this will only create a document, not update the document. Updating the documents would use a put method rather than a post method.

The final part of our application is the endpoint for deleting data.

app.delete("/people", function(req, res) {
    if(!req.body.id) {
        return res.status(400).send({"status": "error", "message": "An `id` is required"});
    }
    database.get(req.body.id).then(function(result) {
        return database.remove(result);
    }).then(function(result) {
        res.send(result);
    }, function(error) {
        res.status(400).send(error);
    });
});


We expect an id to be passed in the request. If this id exists we first do a lookup to make sure the document exists. If the document exists we can delete it. This was all accomplished by chaining JavaScript promises together.

Trying the Finished Project Source Code

If you want a clearer picture on what this application looks like, the complete code can be seen below.

var Express = require("express");
var BodyParser = require("body-parser");
var PouchDB = require("pouchdb");

var app = Express();

app.use(BodyParser.json());
app.use(BodyParser.urlencoded({ extended: true }));

var database = new PouchDB("http://192.168.57.1:4984/example");

app.get("/people", function(req, res) {
    database.allDocs({include_docs: true}).then(function(result) {
        res.send(result.rows.map(function(item) {
            return item.doc;
        }));
    }, function(error) {
        res.status(400).send(error);
    });
});

app.get("/people/:id", function(req, res) {
    if(!req.params.id) {
        return res.status(400).send({"status": "error", "message": "An `id` is required"});
    }
    database.get(req.params.id).then(function(result) {
        res.send(result);
    }, function(error) {
        res.status(400).send(error);
    });
});

app.post("/people", function(req, res) {
    if(!req.body.firstname) {
        return res.status(400).send({"status": "error", "message": "A `firstname` is required"});
    } else if(!req.body.lastname) {
        return res.status(400).send({"status": "error", "message": "A `lastname` is required"});
    }
    database.post(req.body).then(function(result) {
        res.send(result);
    }, function(error) {
        res.status(400).send(error);
    });
});

app.delete("/people", function(req, res) {
    if(!req.body.id) {
        return res.status(400).send({"status": "error", "message": "An `id` is required"});
    }
    database.get(req.body.id).then(function(result) {
        return database.remove(result);
    }).then(function(result) {
        res.send(result);
    }, function(error) {
        res.status(400).send(error);
    });
});

var server = app.listen(3000, function() {
    database.info().then(function(info) {
        console.log(info);
        console.log("Listening on port %s...", server.address().port);
    });
});


To run the application you would execute node app.js from your Terminal or Command Prompt and then hit the http://localhost:3000 endpoints from cURL or whatever application you prefer.

Conclusion

You just saw how to include PouchDB in a server-side Node.js web application where PouchDB communicates to a Couchbase NoSQL database. This was one of many different examples on how you can include mobile and server in the same stack because Sync Gateway is sitting in the middle. In a previous post, I wrote about using the Sync Gateway RESTful API instead of PouchDB. That example also demonstrated mobile and server usage with Couchbase.

Learn how the world’s first NoSQL Engagement Database delivers unparalleled performance at any scale for customer experience innovation that never ends.

Topics:
database ,couchbase ,pouchdb ,node.js ,tutorial ,nosql

Published at DZone with permission of Nic Raboy, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

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

{{ parent.tldr }}

{{ parent.urlSource.name }}