Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

superagent-cache

Package Overview
Dependencies
Maintainers
1
Versions
51
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

superagent-cache - npm Package Compare versions

Comparing version 0.2.1 to 1.0.0

4

package.json
{
"name": "superagent-cache",
"version": "0.2.1",
"version": "1.0.0",
"description": "Superagent with flexible built-in caching.",

@@ -8,3 +8,3 @@ "main": "superagentCache.js",

"superagent": "1.1.0",
"cache-service-cache-module": "1.0.0"
"cache-service-cache-module": "1.1.0"
},

@@ -11,0 +11,0 @@ "devDependencies": {

@@ -9,3 +9,3 @@ # superagent-cache

Require and instantiate superagent-cache as follows to get the [default configuration](#what-does-the-default-configuraiton-give-me):
Require and instantiate superagent-cache as follows to get the [default configuration](#what-does-the-default-configuration-give-me):
```javascript

@@ -73,3 +73,3 @@ var superagent = require('superagent-cache')();

You get the 'default configurations' when you don't provide any params to the `require('superagent-cache')()` command. This will return a fresh instance of `superagent` and bundle an instance of [cacheModule](https://github.com/jpodwys/cache-service-cache-module) for storing data. `cacheModule` is a slim, in-memory cache.
You get the 'default configuration' when you don't provide any params to the `require('superagent-cache')()` command. This will return a fresh instance of `superagent` and bundle an instance of [cacheModule](https://github.com/jpodwys/cache-service-cache-module) for storing data. `cacheModule` is a slim, in-memory cache.

@@ -235,3 +235,3 @@ # How Do I Use a Custom Configuration?

Use this function when you need to override all of your caches' `defaultExpiration` properties (set via cache-service) for a particular cache entry.
Use this function when you need to override your `cache`'s `defaultExpiration` property for a particular cache entry.

@@ -258,2 +258,12 @@ #### Arguments

## .backgroundRefresh(value)
> See the [Using Background Refresh](#using-background-refresh) section for more information.
Tell the underlying `cache` provided in the `require` command to enable background refresh for the generated key and value. If a function is provided, it will use the function, if a boolean is provided, it will use the boolean, if nothing is provided, it will default to true.
#### Arguments
* value: boolean || function || undefined, default: true
## ._end(callback (err, response))

@@ -277,2 +287,73 @@

# Using Background Refresh
With a typical cache setup, you're left to find the perfect compromise between having a long expiration so that users don't have to suffer through the worst case load time, and a short expiration so data doesn't get stale. `superagent-cache` eliminates the need to worry about users suffering through the longest wait time by automatically refreshing keys for you.
#### How do I turn it on?
By default, background refresh is off. It will turn itself on the first time you use the `.backgroundRefresh)` chainable.
#### Setup
`superagent-cache` relies on the background refresh feature of the `cache` param you pass into the `require` command. When you use the `.backgroundRefresh()` chainable, `superagent-cache` passes the provided value into `cache`. This means that if you're using `cache-service`, you almost certainly want `cache-service`'s `writeToVolatileCaches` property set to `true` (it defaults to `true`) so that the data set by background refresh will propogate forward to earlier caches (`cache-service` ONLY background refreshses to the final cache passed to it)
#### Configure
If desired, configure the following properties within `cache`:
* `backgroundRefreshInterval`
* `backgroundRefreshMinTtl`
* `backgroundRefreshIntervalCheck`
#### Use
Background refresh is exposed via the `.backgroundRefresh()` chainable.
When `true` or no param is passed to `.backgroundRefresh()`, it will generate a `superagent` call identical to the one that triggered it and pass that to `cache`.
```javascript
superagent
.get(uri)
.backgroundRefresh()
.end(function (err, response){
//Response will no be refreshed in the background
}
);
```
When a function is passed, it will use that function. Read on for background refresh function requirements.
```javascript
var refresh = function(key, cb){
var response = goGetData();
cb(null, response);
}
superagent
.get(uri)
.backgroundRefresh(refresh)
.end(function (err, response){
//Response will no be refreshed in the background
}
);
```
When `false` is passed, it will do nothing.
#### The Refresh Param
###### refresh(key, cb(err, response))
* key: type: string: this is the key that is being refreshed
* cb: type: function: you must trigger this function to pass the data that should replace the current key's value
The `refresh` param MUST be a function that accepts `key` and a callback function that accepts `err` and `response` as follows:
```javascript
var refresh = function(key, cb){
var response = goGetData();
cb(null, response);
}
```
# More Usage Examples

@@ -332,11 +413,1 @@

* `superagent-cache` is now more flexible, allowing usage of any cache that matches `cache-service`'s API. To make it lighter, then, the hard dependency on `cache-service` was replaced with the much lighter `cacheModule`. As a result, `superagent-cache` can no longer construct a `cache-service` instance for you. If you wish to use `cache-service`, you must instantiate it externally and hand it in as `cache`--the second param in the `require` command.
# Roadmap
* ~~Make it so superagent-cache's `.end()` callback function does not require an `err` param~~
* ~~Make sure that `resetProps()` gets called when `._end()` is called directly~~
* ~~Add unit tests for the various ways headers can be added to calls~~
* ~~Add the 'More Usage Examples' section~~
* ~~Remove the hard dependency on `superagent-cache` and allow users to use any cache that matched `superagent-cache`'s API~~
* Add unit tests for the other points above
* Add thorough comments and param descriptions to the code

@@ -0,1 +1,7 @@

/**
* superagentCache constructor
* @constructor
* @param {superagent instance} agent (optional)
* @param {cache module} cache (optional)
*/
module.exports = function(agent, cache){

@@ -17,2 +23,6 @@

/**
* Whether to execute an http query if the cache does not have the generated key
* @param {boolean} doQuery
*/
Request.prototype.doQuery = function(doQuery){

@@ -23,2 +33,6 @@ props.doQuery = doQuery;

/**
* Remove the given params from the query object after executing an http query and before generating a cache key
* @param {array of strings} pruneParams
*/
Request.prototype.pruneParams = function(pruneParams){

@@ -29,2 +43,6 @@ props.pruneParams = pruneParams;

/**
* Remove the given options from the headers object after executing an http query and before generating a cache key
* @param {boolean} pruneOptions
*/
Request.prototype.pruneOptions = function(pruneOptions){

@@ -35,2 +53,6 @@ props.pruneOptions = pruneOptions;

/**
* Execute some logic on superagent's http response object before caching and returning it
* @param {function} prune
*/
Request.prototype.prune = function(prune){

@@ -41,2 +63,6 @@ props.prune = prune;

/**
* Retrieve a top-level property from superagent's http response object before to cache and return
* @param {string} responseProp
*/
Request.prototype.responseProp = function(responseProp){

@@ -47,2 +73,6 @@ props.responseProp = responseProp;

/**
* Set an expiration for this key that will override the configured cache's default expiration
* @param {integer} expiration (seconds)
*/
Request.prototype.expiration = function(expiration){

@@ -53,2 +83,6 @@ props.expiration = expiration;

/**
* Whether to cache superagent's http response object when it "empty"--especially useful with .prune and .pruneParams
* @param {string} responseProp
*/
Request.prototype.cacheWhenEmpty = function(cacheWhenEmpty){

@@ -59,4 +93,19 @@ props.cacheWhenEmpty = cacheWhenEmpty;

/**
* Initialize a background refresh for the generated key and value
* @param {boolean | function} backgroundRefresh
*/
Request.prototype.backgroundRefresh = function(backgroundRefresh){
props.backgroundRefresh = (typeof backgroundRefresh !== 'undefined') ? backgroundRefresh : true;
return this;
}
/**
* An alias for the .end function because I use ._end and .end for other things
*/
Request.prototype.execute = Request.prototype.end;
/**
* Wraps the .end function so that .resetProps gets called--callable so that no caching logic takes place
*/
Request.prototype._end = function(cb){

@@ -67,2 +116,6 @@ resetProps();

/**
* Execute all caching and http logic
* @param {function} cb
*/
Request.prototype.end = function(cb){

@@ -93,3 +146,7 @@ var curProps = props;

if(!isEmpty(response) || curProps.cacheWhenEmpty){
superagent.cache.set(key, response, curProps.expiration, function(){
var refresh = curProps.backgroundRefresh || null;
if(typeof refresh == 'boolean'){
refresh = getBackgroundRefreshFunction(curProps);
}
superagent.cache.set(key, response, curProps.expiration, refresh, function (){
callbackExecutor(cb, err, response, key);

@@ -127,2 +184,5 @@ });

/**
* Set this.req to null so that future http calls get a branc new req object
*/
Request.prototype.reset = function(){

@@ -132,2 +192,7 @@ this.req = null;

/**
* Generate a cache key unique to this query
* @param {object} reg
* @param {object} cProps
*/
function keygen(req, cProps){

@@ -140,3 +205,3 @@ var cleanParams = null;

}
var options = (req.req && req.req._headers) ? req.req._headers : {};
var options = (req.req && req.req._headers) ? req.req._headers : null;
if(cProps.pruneParams || cProps.pruneOptions){

@@ -148,10 +213,15 @@ cleanParams = (cProps.pruneParams) ? pruneObj(cloneObject(params), cProps.pruneParams) : params;

nameSpace: superagent.cache.nameSpace,
method: req.method,
uri: req.url,
params: cleanParams || params || {},
options: cleanOptions || options || {}
params: cleanParams || params || null,
options: cleanOptions || options || null
});
}
/**
* Convert an array to an object
* @param {array} arr
*/
function arrayToObj(arr){
if(arr){
if(arr && arr.length){
var obj = {};

@@ -171,2 +241,6 @@ for(var i = 0; i < arr.length; i++){

/**
* Convert a string to an object
* @param {string} str
*/
function stringToObj(str){

@@ -189,2 +263,8 @@ if(str){

/**
* Remove properties from an object
* @param {object} obj
* @param {array} props
* @param {boolean} isOptions
*/
function pruneObj(obj, props, isOptions){

@@ -201,2 +281,6 @@ for(var i = 0; i < props.length; i++){

/**
* Simplify superagent's http response object
* @param {object} r
*/
function gutResponse(r){

@@ -213,2 +297,6 @@ var newResponse = {};

/**
* Determine whether a value is considered empty
* @param {*} val
*/
function isEmpty(val){

@@ -218,2 +306,6 @@ return (val === false || val === null || (typeof val == 'object' && Object.keys(val).length == 0));

/**
* Return a cloneof an object
* @param {object} obj
*/
function cloneObject(obj){

@@ -229,2 +321,5 @@ var newObj = {};

/**
* Reset superagent-cache's default query properties
*/
function resetProps(){

@@ -234,2 +329,36 @@ props = {doQuery: true, cacheWhenEmpty: true};

/**
* Generate a background refresh query identical to the current query
* @param {object} curProps
*/
function getBackgroundRefreshFunction(curProps){
return function(key, cb){
key = JSON.parse(key);
var method = key.method.toLowerCase();
var request = superagent
[method](key.uri)
.doQuery(curProps.doQuery)
.pruneParams(curProps.pruneParams)
.pruneOptions(curProps.pruneOptions)
.prune(curProps.prune)
.responseProp(curProps.responseProp)
.expiration(curProps.expiration)
.cacheWhenEmpty(curProps.cacheWhenEmpty);
if(key.params){
request.query(key.params)
}
if(key.options){
request.set(key.options);
}
request.end(cb);
}
}
/**
* Handle the varying number of callback output params
* @param {function} cb
* @param {object} err
* @param {object} response
* @param {string} key
*/
function callbackExecutor(cb, err, response, key){

@@ -250,2 +379,8 @@ if(cb.length === 1){

/**
* Instantates an exception to be thrown
* @param {string} name
* @param {string} message
* @return {exception}
*/
function exception(name, message){

@@ -256,4 +391,2 @@ this.name = name;

var noop = function(){}
if(!agent){

@@ -260,0 +393,0 @@ return superagent;

var expect = require('expect');
var express = require('express');
var superagent = require('superagent');
require('../../superagentCache')(superagent);
var cModule = require('cache-service-cache-module');
var cacheModule = new cModule({backgroundRefreshInterval: 500});
require('../../superagentCache')(superagent, cacheModule);

@@ -123,3 +125,3 @@ var app = express();

});
}, 10);
}, 20);
}

@@ -176,3 +178,3 @@ );

}
)
);
});

@@ -192,3 +194,3 @@

}
)
);
});

@@ -327,2 +329,129 @@

describe('superagentCache background refresh tests', function () {
it('.get() .expiration() .end() background refresh should not work if the chainable is not used', function (done) {
superagent
.get('localhost:3000/one')
.expiration(1)
.end(function (err, response, key){
expect(typeof key).toBe('string');
expect(response.body.key).toBe('one');
setTimeout(function(){
superagent.cache.get(key, function (err, response, key){
expect(response).toBe(null);
done();
});
}, 1500);
}
);
});
it('.get() .expiration() .backgroundRefresh(true) .end() background refresh should refresh a key shortly before expiration', function (done) {
superagent
.get('localhost:3000/one')
.expiration(1)
.backgroundRefresh(true)
.end(function (err, response, key){
expect(typeof key).toBe('string');
expect(response.body.key).toBe('one');
setTimeout(function(){
superagent.cache.get(key, function (err, response){
expect(response.body.key).toBe('one');
done();
});
}, 1500);
}
);
});
it('.get() .query(string&string) .expiration() .end() background refresh should not work if the chainable is not used', function (done) {
superagent
.get('localhost:3000/params')
.query('pruneParams=true&otherParams=false')
.pruneParams(['pruneParams'])
.end(function (err, response, key){
expect(response.body.pruneParams).toBe('true');
expect(response.body.otherParams).toBe('false');
expect(key.indexOf('pruneParams')).toBe(-1);
expect(key.indexOf('otherParams')).toBeGreaterThan(-1);
setTimeout(function(){
superagent.cache.get(key, function (err, response){
expect(response).toBe(null);
done();
});
}, 1500);
}
);
});
it('.get() .query(string&string) .expiration() .backgroundRefresh(true) .end() background refresh should refresh a key shortly before expiration', function (done) {
superagent
.get('localhost:3000/params')
.query('pruneParams=true&otherParams=false')
.pruneParams(['pruneParams'])
.backgroundRefresh(true)
.end(function (err, response, key){
expect(response.body.pruneParams).toBe('true');
expect(response.body.otherParams).toBe('false');
expect(key.indexOf('pruneParams')).toBe(-1);
expect(key.indexOf('otherParams')).toBeGreaterThan(-1);
setTimeout(function(){
superagent.cache.get(key, function (err, response){
expect(response.body.pruneParams).toBe('true');
expect(response.body.otherParams).toBe('false');
expect(key.indexOf('pruneParams')).toBe(-1);
expect(key.indexOf('otherParams')).toBeGreaterThan(-1);
done();
});
}, 1500);
}
);
});
it('.get() .expiration() .backgroundRefresh(function) .end() background refresh should refresh a key shortly before expiration', function (done) {
var refresh = function(key, cb){
cb(null, {body:{key: 'one'}});
}
superagent
.get('localhost:3000/one')
.expiration(1)
.backgroundRefresh(refresh)
.end(function (err, response, key){
expect(typeof key).toBe('string');
expect(response.body.key).toBe('one');
setTimeout(function(){
superagent.cache.get(key, function (err, response){
expect(response.body.key).toBe('one');
done();
});
}, 1500);
}
);
});
it('.get() .expiration() .backgroundRefresh(function) .end() background refresh should refresh a key shortly before expiration', function (done) {
var refresh = function(key, cb){
cb(null, {body:{key: 'two'}});
}
superagent
.get('localhost:3000/one')
.expiration(1)
.backgroundRefresh(refresh)
.end(function (err, response, key){
expect(typeof key).toBe('string');
expect(response.body.key).toBe('one');
setTimeout(function(){
superagent.cache.get(key, function (err, response){
expect(response.body.key).toBe('two');
done();
});
}, 1500);
}
);
});
});
});
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc