You don’t need a library to interact with Cloudant or Apache CouchDB™: its HTTP API means that any device that can speak HTTP can read or write data. A phone, a browser, a fridge — anything. If you’re a Node.js developer, then the Nano library provides just enough scaffolding to help you along without getting in the way of your code. The Cloudant Node.js Library builds on Nano, adding some extra functions that are Cloudant-specific.

Today sees the release of version 1.5 of the Cloudant Node.js Library, which adds the following features over the previous release:

  • Keep-Alive is on by default
  • Pluggable request functions

spiral cable guitar plug

Let’s deal with each in turn.

Keep-Alive

In previous versions of the Cloudant library, the socket connection between your app and the Cloudant instance was discarded after each request. This follows the default behaviour of Node.js’s built-in HTTP functions. With version 1.5, we have changed the default behaviour to keep sockets open so that they can be reused by future API calls. This brings performance benefits because HTTPS requires a chatty setup conversation between client and server which is avoided when a second request reuses a pre-existing connection. By reducing the number of new socket connections, we can get to work faster and deliver a greater throughput. Cloudant is happy to keep sockets alive and now the library is following its lead.

This “Keep-Alive” behaviour has always been available as an option with our library, but v1.5 sees it become the default behaviour. If you need a different configuration, then you can still pass your own HTTP agent as requestDefaults.agent at startup.

Plugins

Working on a library is a challenge not least because its users expect new features, but are also keen to avoid the imposition of breaking changes to the library’s API. Version 1.5 adds some new features to the way the library delivers outgoing requests, but its default behaviour is unchanged. When setting up the library you can opt for one of three different plugins, or provide your own:

  1. ‘default’ – the library’s normal behaviour: every function call results in a single outgoing HTTP request. Your code receives the response as a JavaScript ‘callback’, or the return value of the function can be piped to use Node.js’s Stream API.
  2. ‘retry’ – each function call may result in multiple HTTP requests, as the request will be retried if Cloudant replies with an HTTP 429 response.
  3. ‘promises’ – instead of passing in a callback function to each library call, the library will return a Promise that is resolved when the HTTP request completes.
  4. custom – write your own request handler!

The ‘default’ plugin – for callbacks and streaming

If no plugin is specified, then the pre-1.5 behaviour is retained.

var cloudant = require('cloudant')({url:myurl});
var db = cloudant.db.use('mydb');

// responses are provided to your callback function
db.get('mydoc', function(err, data) {
});

// or can be piped to a stream
db.list().pipe(process.stdout);

The ‘retry’ plugin – for configurable retries

When Cloudant is delivered in its multi-tenant flavour, we have to ensure that one user doesn’t cause problems for other users sharing the same physical hardware. Cloudant may, from time to time, return an HTTP 429 response code which instructs the caller to try the request again at a later time because the caller has exceeded its allotted API call rate.

The ‘retry’ plugin will automatically retry requests if a 429 response is received.

var cloudant = require('cloudant')({url: myurl, plugin: 'retry'});
var db = cloudant.db.use('mydb');

// responses are provided to your callback function as normal
db.get('mydoc', function(err, data) {
});

By default, up to three API calls are attempted with a delay of 500ms (doubling after each attempt). These defaults are also configurable by you:

var cloudant = Cloudant({url: myurl, plugin:'retry', retryAttempts:5, retryTimeout:1000 });

N.B.

  • you may still get called back with an ‘err’ containing a 429 response if the last retry attempt returned a 429
  • you cannot use the Node.js streaming API when using the ‘retry’ plugin, only callbacks
  • dedicated and local Cloudant customers (i.e., not on Cloudant multi-tenant) do not get 429 responses. 429s are only used to prevent “noisy neighbours” in multi-tenant deployments.

The ‘promises’ plugin – for cleaner code

You may now use Promises to handle asynchronous calls in the Cloudant library. Simply start up the library using the ‘promises’ plugin:

var cloudant = require('cloudant')({url: myurl, plugin: 'promises'});
var db = cloudant.db.use('mydb');
db.list().then(function(data){
  // success
}).catch(function(e) {
  // failure
});

N.B.

  • you cannot use the Node.js streaming API when using the ‘promises’ plugin

Bring your own plugin

As well as picking up one of the built-in plugins, you can provide your own request-like function to handle the HTTP traffic yourself.

var doNothingPlugin = function(opts, callback) {
  // don't do anything, just pretend that everything's ok.
  callback(null, { statusCode:200 }, { ok: true });
};
var cloudant = Cloudant({url: myurl, plugin: doNothingPlugin});

A more useful example would be to add in a caching layer using cachemachine:

var cachePlugin = require('cachemachine')();
var cloudant = Cloudant({url: myurl, plugin: cachePlugin});

Now every outgoing GET request is cached so that repeated requests are retrieved from memory instead of hitting Cloudant.

What if I want multiple plugins in the same app?

You can!

var Cloudant = require('cloudant');
var cloudantPromises = Cloudant({url: myurl, plugin: 'promises'});
var cloudantStreaming = Cloudant({url: myurl});

Conclusion

The Node.js Cloudant Library is an open-source project. All issues, pull requests and comments are greatly appreciated.

Join The Discussion

Your email address will not be published. Required fields are marked *