Name: node-rest-cache
Owner: Reddit
Description: An LRU-based caching solution for rest-like data fetching.
Created: 2015-10-30 18:19:58.0
Updated: 2018-03-03 20:45:41.0
Pushed: 2016-03-11 00:36:07.0
Homepage: null
Size: 34
Language: JavaScript
GitHub Committers
User | Most Recent Commit | # Commits |
---|
Other Committers
User | Most Recent Commit | # Commits |
---|
A caching solution for data fetching. Reduces the number of API calls you have
This cache turns a request, such as api.listings.get({ subreddit: 'funny '})
into two caches:
The intent is that you can now run api.listings.get({ id: 1 })
, and if the
previous query had already populated a listing
with id 1
, you get an
immediate response rather than making another server round-trip.
You can also reset specific instances of objects in the cache, for example, on
the event of a patch
that edits an object.
(See ./test for examples)
The constructor, new Cache({ })
, takes settings:
rules
, a list of rules that operate on the parameters passed into an api request.
Rules are functions that return booleans: if they return false, the cache
is skipped (and does not invalidate the data cache.)defaultRequestCacheConfig
, the default config for all API calls if a config is not
specified. The cache
rules here also set the default request cache LRU
settings. defaultRequestCacheConfig.cache
uses the same parameters as the
LRU.dataTypes
is an object that contains key
- config
pairs. The config
optionally contains idProperty
, which defaults to id
if not set (this
is how the request IDs are mapped to the data IDs), and cache
, which
is the LRU cache config. (If not specified, uses the default as noted above.)The primary function, cache.get
, takes a series of arguments:
key
, used to look up a cache of ids returned by a given. This can be
ommitted if your function has a unique name
(function.name
){ datatype: data }
so that the
cache can put data into the proper place. (This also means you can work with
multiple data types at once.)The cache will generate a key based on a sha1 of the JSON.stringified parameters. It will then look up a list of IDs returned for that key+sha. If it does not exist, it will return a Promise, and attempt to resolve the function passed in with the parameters supplied. It will pass on a promise rejection, or if it is successful, it will:
If the data is in the cache, it will:
Promise.resolve
d immediately. If not, the above process will
be run, as we will assume the cache is stale.Another function, cache.resetData
, allows you to reset a single object, a list of
objects, or to reset a cache entirely for a given data type. It takes the
arguments:
It will attempt to match the object (or, each object in the array), and replace the objects in the cache with the supplied data. Or, if none was passed in, the cache will be cleared for that data type.
If no arguments are provided, it will reset the entire data cache.
You can also use cache.resetRequests()
to reset the request cache. It takes
up to three optional arguments as well:
If only key is used, the entire cache for that key will be reset; if both, then it will reset for that single reset; if key, parameters, and ids are sent, it will update the ids to the passed-in list.
If no arguments are provided, it will reset the entire request cache.
{ headers:{}, body:{} }
, and responses
from restcache will follow the same format. This allows HTTP headers to be
passed around. The contents of headers
can be anything, and will be stored in
an LRU with the same configration as the request's LRU.body
must be formatted as { datatype: [data] }
to be stored in the caches
properly. Use the format
option to set up your data properly.tion loggedOut (params) {
turn !params.token;
cache = new cache.get({
les: {
loggedOut: function(params) {
return !params.token;
},
faultRequestCacheConfig: {
cache: {
max: 50, //50 items
length: function(n) { return n.length }, //how length is determined
dispose: function(key, n) { n.close() }, // optional handling on disposal
maxAge: 1000 * 60 * 5, // 5 minutes
},
rules: [ loggedOut ]
taTypes:
listings: {
idProperty: '_id',
cache: {
max: 75,
maxAge: 1000 * 60 * 3
}
},
comments: {
cache: false, // don't cache comments
}
tion formatListings(data) {
turn { listings: data };
tion unFormatListings(data) {
turn data.listings;
tion getData(url) {
turn new Promise(function(resolve, reject) {
superagent
.get(url)
.then(function(err, res) {
if(err) { return reject(err); }
resolve({
headers: res.headers,
body: res.body
});
});
;
apiParams = { subreddit: 'funny' };
se `api.listings.get.name` as the key, and use the default config.
listings = cache.get(api.listings.get, [apiParams], {
rmat: formatListings
format: unformatListings
ings.then(
nction(data) { /*...*/ },
nction(error) { /*...*/ }
se a custom key and config. Because it has a different key, it will force a
ache refresh of the listing in question, even though it may already be in
he listing cache.
apiParams = { subreddit: 'funny' };
apiParameters = { _id: 1 };
key = 'edit-listing-cache';
listing = cache.get(
key,
api.listings.get,
[apiParams],
{
format: formatListings,
unformat: unformatListings
}
);
ing.then(
nction(listings) { /*...*/ },
nction(error) { /*...*/ }
eset an object in the cache that was updated
listings.patch(params).then(function(res) {
che.resetData('listings', res.listing);
bliterate the cache
e.resetData('listings');
oad a single object
apiParams = { id: 17 };
e.getById('listings', apiParams.id, api.listings.get, [apiParams], {
rmat: formatListings,
format: unformatListings
elete an object, then fix the caches
listings.delete(17).then(function(res) {
Remove the object from the data cache
che.deleteData('listings', 17);
Optionally force-reset the request if you know the params ahead of time
che.resetRequests(api.listings.get, [], { listings: [15,16,18] });
Promise
, provided by iojs, node
harmony, and some ES6 transpilers such as babel.