expeditious
expeditious is a generic caching API that can read/write key value pairs
from/to compatible caching "engines". Engines enable you to easily switch cache
storage providers e.g from in node.js memory cache to redis, if desired.
Install
You know the drill...
npm install expeditious --save
Example
var expeditious = require('expeditious');
var words = expeditious({
namespace: 'words',
engine: require('expeditious-engine-memory')(),
defaultTtl: (60 * 1000)
});
words.set({
key: 'fáilte',
value: 'An Irish Gaelic word meaning "hello"'
}, function (err) {
if (err) {
console.error('failed to set item in the words cache');
} else {
console.log('added an item to the words cache')
}
});
Debugging
If you need some debug logging from this module then it can be enabled using
a DEBUG
environment variable. This is because we use the debug
module for
logging.
Here's the general format:
export DEBUG=expeditious@$EXPEDITIOUS_VERSION-$NAMESPACE
For example, if you were using expeditious 0.2.0 had a logger with the namespace
users then the following would allow it to write debug logs:
export DEBUG=expeditious@0.2.0-users
Alternatively you can enable logging for all 0.2.0 loggers like so:
export DEBUG=expeditious@0.2.0-*
API
expeditious.ExpeditiousEngine
The base class/constructor that can be used to create your own engines. More
info is provided below in the Custom Storage Engines section.
expeditious(opts)
require-ing expeditious returns a factory function that can be called to
create an expeditious instance. opts must be an Object and can contain the
following keys:
- namespace ([String] Required) - namespace for keys. Used to avoid clashes
with other expeditious instances that might be using the same opts.engine.
- engine ([String] Required) - ExpeditiousEngine that communicates with
the underlying cache datastore
- defaultTtl ([Number] Required) - number of milliseconds to wait before
considering an entry expired
- objectMode ([Boolean] Optional) - Determines if this expeditious instance
should automatically attempt to JSON.parse and JSON.stringify entries on
set and get calls. This will be performed safely, so if an exception occurs
it will be returned as the err param.
instance
Every instance function accepts a params Object. set/get/del/ttl functions require params.key. Each function
accepts a callback that is called with the typical fn(err, res) pattern in
node.js.
instance.set(params[, callback])
Set an item in the underlying cache store, having an optional callback
triggered on success or failure. params.key should be a String and
params.val should be an Object or String depending on the objectMode flag.
instance.get(params, callback)
Get an item from the cache. params requires a key option that should be a
String.
instance.keys(params, callback)
Fetch all keys in the cache. No params are supported yet, but we include it for
future support.
instance.ttl(params, callback)
Get the remaining milliseconds before the cache entry identified by
params.key expires. Returns null as the result if params.key does not exist.
instance.flush(params[, callback])
Flush all keys from the cache. Similar to instance.keys, no params are
supported yet, but we include it for future support.
instance.del(params[, callback])
Delete a cache entry identified by params.key. Callback will be passed an
Error if one occurred.
Examples
String Mode
By default expeditious expects to receive String values to set calls, and it
will return String values too. An example is below:
var expeditious = require('expeditious');
var words = expeditious({
namespace: 'words',
engine: require('expeditious-engine-memory')(),
defaultTtl: (60 * 1000)
});
words.set({
key: 'fáilte',
value: 'An Irish Gaelic word meaning "hello"'
}, onItemSet);
function onItemSet (err) {
if (err) {
console.log('failed to set definition for "fáilte"');
} else {
loadItem();
}
}
function loadItem () {
words.get({
key: 'fáilte'
}, function (err, definitionStr) {
if (err) {
console.error('hmm, we failed to load definition for "fáilte"');
} else {
console.log('here is definition for the word "fáilte"', definitionStr);
}
});
}
Object Mode
Optionally you can enable objectMode when using expeditious to have it
seamlessly convert items to and from JSON format as demonstrated below.
var expeditious = require('expeditious');
var words = expeditious({
namespace: 'words',
engine: require('expeditious-engine-memory')(),
defaultTtl: (60 * 1000),
objectMode: true
});
words.set({
key: 'fáilte',
value: {
definition: 'An Irish Gaelic word meaning "hello"'
}
}, onItemSet);
function onItemSet (err) {
if (err) {
console.log('failed to set data for "fáilte"');
} else {
loadItem();
}
}
function loadItem () {
words.get({
key: 'fáilte'
}, function (err, definitionJson) {
if (err) {
console.error('hmm, we failed to load json for "fáilte"');
} else {
console.log('here is json for the word "fáilte"', definitionJson);
}
});
}
Storage Engines
An engine is an implementation of the ExpeditiousEngine constructor.
Typically an engine will use a database, Redis, or process memory to store
data, but you can create an engine to store any data format.
Existing Engines
Here's a list of existing engines that you can use right now:
- expeditious-engine-memory
Custom Engines
You can create a custom engine by inheriting from ExpeditiousEngine and
implementing the required functions. If a function is not implemented in your
subclass it will use the default behaviour of returning an error stating that
the called function is not implemented.
Below is an example of an incomplete custom engine. For the full prototype
definition see the Engine constructor
var ExpeditiousEngine = require('expeditious').ExpeditiousEngine;
var util = require('util');
function CustomEngine (opts) {
ExpeditiousEngine.call(this);
this.entries = {};
}
util.inherits(CustomEngine, ExpeditiousEngine);
module.exports = CustomEngine;
CustomEngine.prototype.get = function (namespacedKey, callback) {
callback(null, this.entries[namespacedKey].value);
};
CustomEngine.prototype.set = function (namespacedKey, val, exp, callback) {
var self = this;
self.entries[namespacedKey] = {
value: val
};
setTimeout(function () {
delete self.entries[namespacedKey];
}, exp);
callback(null);
};
Contributing
Contributions are always welcome, just open a PR and add/fix tests for new/changed functionality. If you are unsure about a PR you have in mind, then open an issue for discussion.
Changelog
- 1.0.0 - Initial stable release. No API changes from 0.2.0.