Choosing a Cloudant library

July 12, 2017 | Glynn Bird | Library Node.js

The beauty of Apache CouchDB and Cloudant is that you don’t need to a library to be able to start using it. Some databases require a “driver” module to be installed to handle communication between your application and your database, but when your database speaks HTTP then you only need curl, a web browser, or anything that can make web requests. For example:

Sometimes developers need a little help. To avoid repeating the same low-level code, to abstract the API calls into more semantically meaningful methods, and to make life easier we often employ libraries.

library

Photo by Tobias Fischer on Unsplash

In this article we’ll explore some options that a JavaScript/Node.js developer could choose when writing code against CouchDB or Cloudant, from the lowest level to the highest.

Level 0 - no libraries

If you want to learn the HTTP in detail, then you can choose to use no libraries whatsoever:

const url = 'https://examples.cloudant.com';
const db = 'appointments';
const https = require('https');
const req = https.request(url + '/' + db + '/_all_docs?include_docs=true', (res) => {
  res.on('data', (chunk) => {
    process.stdout.write(chunk);
  });
});

req.on('error', (e) => {
  console.error(e.message);
});
req.end();

This approach uses the Node.js https library to make a single API call. It leaves you to formulate your own URL and to join the separate chunks of reply data into a complete JSON response.

Level 1 - an HTTP request library

To help with formulating HTTP requests, there a several third-party HTTP libraries to choose from. I usually go for request, but others are available.

var request = require('request');
const url = 'https://examples.cloudant.com';
const db = 'appointments';
var r = {
  method: 'get',
  url: url + '/' + db + '/_all_docs',
  qs: {
    include_docs: true
  },
  json: true
};
request(r, function(err, response, body) {
  console.log(body);
}); 

The request module makes it simpler to deal with HTTP requests, and if you ask it nicely, it will parse the JSON response for you too. You still get to learn the CouchDB API, but the mechanics of making the HTTP call are simplified.

Level 2 - the Nano library

Nano is an open-source project that was donated to the Apache Software Foundation and has become the official Node.js library for CouchDB.

It doesn’t actually do much — it is a thin wrapper around CouchDB’s API — but it does make your code a little easier to write and to maintain:

var nano = require('nano');
const url = 'https://examples.cloudant.com';
const db = 'appointments';
var mydb = nano(url).db.use(db);
mydb.list({include_docs:true}, function(err, data) {
  console.log(data);
});

Using Nano allows you to abstract the API calls away. In this case, the list function makes a GET /db/_all_docs API call. You can use the Nano library and not know what API calls are being made on your behalf.

Level 3 - the Cloudant library

The Cloudant library extends Nano to add:

Here’s how you could use Promises instead of callbacks:

var cloudant = require('cloudant');
const url = 'https://examples.cloudant.com';
const db = 'appointments';
var mydb = cloudant({url: url, plugin:'promises'}).db.use(db);
mydb.list({include_docs:true}).then(console.log);

Some of the plugins make multiple API calls for one function call (e.g., swap your Cloudant credentials for a token), then make a second API call to fetch the data you need passing the token. You don’t see the individual API calls, just the response.

Level 4 - PouchDB

You can use PouchDB as an HTTP-only client too:

var PouchDB = require('pouchdb-http');
const url = 'https://examples.cloudant.com/appointments';
var db = new PouchDB(url);
db.allDocs({include_docs:true}).then(console.log);

It has its own naming convention for functions, but function calls result in the equivalent API call. If you’re developing with PouchDB on the client side, it may be easier to stick with the same API to deal with your server-side CouchDB or Cloudant database.

Level 5 - the cloudant-quickstart library

The cloudant-quickstart library builds on the request library, not on Nano. It provides a different abstraction from the Cloudant API, hiding some of the complexities that confuse first-time users and providing higher-level simplifications.

const url = 'https://examples.cloudant.com/appointments';
const mydb = require('cloudant-quickstart')(url);
mydb.all().then(console.log);

The data returned by cloudant-quickstart doesn’t necessarily match the data from the Cloudant API. It tidies up and simplifies returned data, removing revision tokens and complicated scaffolding.

It also abstracts the creation of indicies, which means that performing an aggregation on a data set no longer requires users to understand the CouchDB MapReduce system:

// get sum of the price grouped by country & state
mydb.sum('price', ['country', 'state']);

Alternatives

The great thing about open-source is that you aren’t limited to “official” products. If you don’t like the tools, help improve the open-source offerrings by raising issues or submitting code — find alternative tools or build your own! You can choose whether you’re looking for a library that can do callbacks or Promises and whether it allows you to learn the CouchDB API or hides it from you.

In my opinion, it makes sense to get started with a high-level library that abstracts and hides details from you at first. It allows you to build more quickly with less distraction. As you get more serious in your work, you may find you need to see more detail and switch to a lower-level of abstraction.