cache-manager-express-mw
Advanced tools
Comparing version 0.1.0 to 0.2.1
{ | ||
"name": "cache-manager-express-mw", | ||
"version": "0.1.0", | ||
"version": "0.2.1", | ||
"description": "Middleware for Express that uses cache-manager to add a caching layer in front of your application.", | ||
@@ -11,3 +11,3 @@ "main": "src/index.js", | ||
"type": "git", | ||
"url": "git+https://github.com/afrasso/cache-manager-express-mw.git" | ||
"url": "git+https://github.com/Cimpress-MCP/cache-manager-express-mw.git" | ||
}, | ||
@@ -19,8 +19,12 @@ "keywords": [ | ||
], | ||
"author": "Anthony Frasso", | ||
"author": "Cimpress-MCP", | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/afrasso/cache-manager-express-mw/issues" | ||
"url": "https://github.com/Cimpress-MCP/cache-manager-express-mw/issues" | ||
}, | ||
"homepage": "https://github.com/afrasso/cache-manager-express-mw#readme", | ||
"homepage": "https://github.com/Cimpress-MCP/cache-manager-express-mw#readme", | ||
"dependencies": { | ||
"bluebird": "^3.4.1", | ||
"lodash": "^4.15.0" | ||
}, | ||
"devDependencies": { | ||
@@ -33,11 +37,7 @@ "chai": "^3.5.0", | ||
"grunt-mocha-istanbul": "^5.0.2", | ||
"grunt-mocha-test": "^0.12.7", | ||
"grunt-mocha-test": "^0.13.2", | ||
"mocha": "^3.0.2", | ||
"mocha-istanbul": "^0.3.0", | ||
"node-uuid": "^1.4.7" | ||
}, | ||
"dependencies": { | ||
"bluebird": "^3.4.1", | ||
"lodash": "^4.15.0" | ||
} | ||
} |
@@ -43,9 +43,19 @@ # cache-manager-express-mw | ||
| Property | Default | Description | | ||
| ---------|-----------|-----------------------------------------------------------------------------------------------| | ||
| prefix | undefined | A prefix to append to the front of the generated cache key in case differentiation is needed. | | ||
| defaults | undefined | An object containing query string default values so that a missing query string value and the specified default resolve to the same cache key. For example, ```{ defaults: { val: "abc" } }``` will ensure that the routes ```/a/b/c``` and ```/a/b/c?val=abc``` resolve to the same cache key.| | ||
| Property | Default | Description | | ||
| ----------|-----------|-----------------------------------------------------------------------------------------------| | ||
| prefix | undefined | A prefix to append to the front of the generated cache key in case differentiation is needed. | | ||
| defaults | undefined | An object containing query string default values so that a missing query string value and the specified default resolve to the same cache key. For example, ```{ defaults: { val: "abc" } }``` will ensure that the routes ```/a/b/c``` and ```/a/b/c?val=abc``` resolve to the same cache key.| | ||
| callbacks | undefined | An object containing one or more callback functions (see [Callbacks](#callbacks) below). | ||
## Callbacks | ||
It is possible to specify callback functions that are called when an during attempts to retrieve a value from the cache: | ||
* `onAttempt(key)`: executed when any attempt is made to retrieve a value from the cache | ||
* `onHit(key, value)`: executed when a cache hit occurs and the value is retrieved from the cache | ||
* `onMiss(key)`: executed when a cache miss occurs and the value is not present in the cache | ||
* `onError(err, key)`: executed when an error occurs during the attempt to retrieve a value from the cache | ||
## License | ||
[MIT](LICENSE) |
@@ -15,3 +15,3 @@ { | ||
"cache-manager-express-mw": "file:..", | ||
"cache-manager-redis": "^0.2.3", | ||
"cache-manager-redis": "^0.2.4", | ||
"express": "^4.14.0" | ||
@@ -25,3 +25,3 @@ }, | ||
"grunt-mocha-istanbul": "^5.0.2", | ||
"grunt-mocha-test": "^0.12.7", | ||
"grunt-mocha-test": "^0.13.2", | ||
"grunt-node-inspector": "^0.4.2", | ||
@@ -28,0 +28,0 @@ "grunt-nodemon": "^0.4.2", |
@@ -8,5 +8,27 @@ var _ = require("lodash"), | ||
var app = express(); | ||
var cache = cacheManager.caching({ store: redisStore }); | ||
var cacheOptions = { | ||
store: redisStore, | ||
retry_strategy: function() { // jscs:ignore requireCamelCaseOrUpperCaseIdentifiers | ||
return; | ||
} | ||
}; | ||
var cache = cacheManager.caching(cacheOptions); | ||
app.get("/", cacheManagerExpress(cache), function(req, res) { | ||
var callbacks = { | ||
onHit: function(key, value) { | ||
console.log(`Cache hit! key=${key}, value=${value.body}`); | ||
}, | ||
onMiss: function(key) { | ||
console.log(`Cache miss! key=${key}`); | ||
}, | ||
onError: function(err, key) { | ||
console.log(`Cache error! err=${err}, key=${key}`); | ||
}, | ||
onAttempt: function(key) { | ||
console.log(`Cache attempt! key=${key}`); | ||
} | ||
}; | ||
var options = { defaults: { toUpper: false }, callbacks: callbacks }; | ||
app.get("/", cacheManagerExpress(cache, options), function(req, res) { | ||
res.set("cache-control", `private, max-age=300`); | ||
@@ -16,3 +38,3 @@ return res.send("Hello World!"); | ||
app.get("/echo", cacheManagerExpress(cache, { defaults: { toUpper: false } }), function(req, res) { | ||
app.get("/echo", cacheManagerExpress(cache, options), function(req, res) { | ||
if (req.query.message) { | ||
@@ -19,0 +41,0 @@ var message = req.query.message; |
@@ -12,2 +12,5 @@ var _ = require("lodash"), | ||
var getValue = function(key) { | ||
if (_.get(options, "callbacks.onAttempt")) { | ||
options.callbacks.onAttempt(key); | ||
} | ||
var cacheGet = Promise.promisify(cache.get); | ||
@@ -19,2 +22,5 @@ return cacheGet(key) | ||
} | ||
if (_.get(options, "callbacks.onError")) { | ||
options.callbacks.onError(err, key); | ||
} | ||
}); | ||
@@ -33,3 +39,5 @@ }; | ||
} | ||
throw err; | ||
if (_.get(options, "callbacks.onError")) { | ||
options.callbacks.onError(err, key); | ||
} | ||
}); | ||
@@ -53,6 +61,8 @@ }; | ||
if (_.get(options, "callbacks.onHit")) { | ||
options.callbacks.onHit(key, value); | ||
} | ||
return getTtl(key) | ||
.then(ttl => { | ||
setCacheControlHeader(res, value.accessibility, ttl); | ||
}) | ||
.then(ttl => setCacheControlHeader(res, value.accessibility, ttl)) | ||
.then(() => { | ||
@@ -67,7 +77,9 @@ // This is dumb, but it results in a prettier JSON format | ||
}) | ||
.return(true) | ||
.catch(err => false); | ||
.return(true); | ||
}; | ||
var handleCacheMiss = function(res, key) { | ||
if (_.get(options, "callbacks.onMiss")) { | ||
options.callbacks.onMiss(key); | ||
} | ||
var send = res.send.bind(res); | ||
@@ -92,2 +104,5 @@ | ||
} | ||
if (_.get(options, "callbacks.onError")) { | ||
options.callbacks.onError(err, key); | ||
} | ||
}); | ||
@@ -115,8 +130,2 @@ } | ||
} | ||
}) | ||
.catch(err => { | ||
if (!isProduction()) { | ||
console.warn("Error accessing cache: " + err); | ||
} | ||
next(); | ||
}); | ||
@@ -123,0 +132,0 @@ }; |
@@ -34,3 +34,10 @@ var _ = require("lodash"), | ||
context.options = { }; | ||
context.options = { | ||
callbacks: { | ||
onHit: chai.spy(function() { }), | ||
onMiss: chai.spy(function() { }), | ||
onError: chai.spy(function() { }), | ||
onAttempt: chai.spy(function() { }) | ||
} | ||
}; | ||
@@ -90,2 +97,7 @@ context.cachingMiddleware = cacheManagerExpress(context.cacheWrapper, context.options); | ||
expect(context.next).to.be.a.spy.and.to.have.been.called(); | ||
expect(context.options.callbacks.onHit).to.be.a.spy.and.to.not.have.been.called(); | ||
expect(context.options.callbacks.onMiss).to.be.a.spy.and.to.not.have.been.called(); | ||
expect(context.options.callbacks.onError).to.be.a.spy.and.to.not.have.been.called(); | ||
expect(context.options.callbacks.onAttempt).to.be.a.spy.and.to.not.have.been.called(); | ||
}); | ||
@@ -112,2 +124,7 @@ }); | ||
expect(context.next).to.be.a.spy.and.to.have.been.called(); | ||
expect(context.options.callbacks.onHit).to.be.a.spy.and.to.not.have.been.called(); | ||
expect(context.options.callbacks.onMiss).to.be.a.spy.and.to.have.been.called(); | ||
expect(context.options.callbacks.onError).to.be.a.spy.and.to.not.have.been.called(); | ||
expect(context.options.callbacks.onAttempt).to.be.a.spy.and.to.have.been.called(); | ||
}); | ||
@@ -117,2 +134,24 @@ }); | ||
describe("Getting a request that has not been cached before and options is undefined", function() { | ||
it("should cache the response successfully", function() { | ||
context.options = undefined; | ||
context.cachingMiddleware(context.request, context.response, context.next); | ||
return checkDone(context.doneCondition) | ||
.then(() => { | ||
expect(context.cacheWrapper.get).to.be.a.spy.and.to.have.been.called(); | ||
expect(context.cacheWrapper.ttl).to.be.a.spy.and.to.not.have.been.called(); | ||
expect(context.response.set).to.be.a.spy.and.to.not.have.been.called(); | ||
expect(context).to.not.have.property("cacheControlHeaderValue"); | ||
expect(context.response.get).to.be.a.spy.and.to.have.been.called(); | ||
expect(context.cacheWrapper.set).to.be.a.spy.and.to.have.been.called(); | ||
expect(context.cache).to.exist.and.be.an("object"); | ||
expect(context.cache).to.have.property("GET:/a/b/c").and.deep | ||
.equal({ statusCode: context.statusCode, body: context.body, accessibility: context.accessibility }); | ||
expect(context.status).to.be.a.spy.and.to.have.been.called(); | ||
expect(context.send).to.be.a.spy.and.to.have.been.called(); | ||
expect(context.next).to.be.a.spy.and.to.have.been.called(); | ||
}); | ||
}); | ||
}); | ||
describe("Getting a request that has been cached before", function() { | ||
@@ -141,2 +180,7 @@ it("should return the cached response successfully", function() { | ||
expect(context.next).to.be.a.spy.and.to.not.have.been.called(); | ||
expect(context.options.callbacks.onHit).to.be.a.spy.and.to.have.been.called(); | ||
expect(context.options.callbacks.onMiss).to.be.a.spy.and.to.not.have.been.called(); | ||
expect(context.options.callbacks.onError).to.be.a.spy.and.to.not.have.been.called(); | ||
expect(context.options.callbacks.onAttempt).to.be.a.spy.and.to.have.been.called(); | ||
}); | ||
@@ -146,2 +190,30 @@ }); | ||
describe("Getting a request that has been cached before and options in undefined", function() { | ||
it("should return the cached response successfully", function() { | ||
context.options = undefined; | ||
context.cache["GET:/a/b/c"] = { | ||
statusCode: context.statusCode, | ||
body: context.body, | ||
accessibility: context.accessibility | ||
}; | ||
context.cachingMiddleware(context.request, context.response, context.next); | ||
return checkDone(context.doneCondition) | ||
.then(() => { | ||
expect(context.cacheWrapper.get).to.be.a.spy.and.to.have.been.called(); | ||
expect(context.cacheWrapper.ttl).to.be.a.spy.and.to.have.been.called(); | ||
expect(context.response.set).to.be.a.spy.and.to.have.been.called(); | ||
expect(context).to.have.property("cacheControlHeaderValue").and | ||
.equal(`${context.accessibility}, max-age=${context.ttl}`); | ||
expect(context.response.get).to.be.a.spy.and.to.not.have.been.called(); | ||
expect(context.cacheWrapper.set).to.be.a.spy.and.to.not.have.been.called(); | ||
expect(context.cache).to.exist.and.be.an("object"); | ||
expect(context.cache).to.have.property("GET:/a/b/c").and.deep | ||
.equal({ statusCode: context.statusCode, body: context.body, accessibility: context.accessibility }); | ||
expect(context.status).to.be.a.spy.and.to.have.been.called(); | ||
expect(context.send).to.be.a.spy.and.to.have.been.called(); | ||
expect(context.next).to.be.a.spy.and.to.not.have.been.called(); | ||
}); | ||
}); | ||
}); | ||
describe("Handling a response without a cache control header when it has not been cached", function() { | ||
@@ -166,2 +238,7 @@ it("should return but not cache the response", function() { | ||
expect(context.next).to.be.a.spy.and.to.have.been.called(); | ||
expect(context.options.callbacks.onHit).to.be.a.spy.and.to.not.have.been.called(); | ||
expect(context.options.callbacks.onMiss).to.be.a.spy.and.to.have.been.called(); | ||
expect(context.options.callbacks.onError).to.be.a.spy.and.to.not.have.been.called(); | ||
expect(context.options.callbacks.onAttempt).to.be.a.spy.and.to.have.been.called(); | ||
}); | ||
@@ -191,2 +268,7 @@ }); | ||
expect(context.next).to.be.a.spy.and.to.have.been.called(); | ||
expect(context.options.callbacks.onHit).to.be.a.spy.and.to.not.have.been.called(); | ||
expect(context.options.callbacks.onMiss).to.be.a.spy.and.to.have.been.called(); | ||
expect(context.options.callbacks.onError).to.be.a.spy.and.to.have.been.called(); | ||
expect(context.options.callbacks.onAttempt).to.be.a.spy.and.to.have.been.called(); | ||
}); | ||
@@ -213,4 +295,4 @@ }); | ||
expect(context).to.not.have.property("cacheControlHeaderValue"); | ||
expect(context.response.get).to.be.a.spy.and.to.have.been.called(); | ||
expect(context.cacheWrapper.set).to.be.a.spy.and.to.have.been.called(); | ||
expect(context.response.get).to.be.a.spy.and.to.not.have.been.called(); | ||
expect(context.cacheWrapper.set).to.be.a.spy.and.to.not.have.been.called(); | ||
expect(context.cache).to.exist.and.be.an("object"); | ||
@@ -221,3 +303,8 @@ expect(context.cache).to.have.property("GET:/a/b/c").and.deep | ||
expect(context.send).to.be.a.spy.and.to.have.been.called(); | ||
expect(context.next).to.be.a.spy.and.to.have.been.called(); | ||
expect(context.next).to.be.a.spy.and.to.not.have.been.called(); | ||
expect(context.options.callbacks.onHit).to.be.a.spy.and.to.have.been.called(); | ||
expect(context.options.callbacks.onMiss).to.be.a.spy.and.to.not.have.been.called(); | ||
expect(context.options.callbacks.onError).to.be.a.spy.and.to.have.been.called(); | ||
expect(context.options.callbacks.onAttempt).to.be.a.spy.and.to.have.been.called(); | ||
}); | ||
@@ -246,2 +333,7 @@ }); | ||
expect(context.next).to.be.a.spy.and.to.have.been.called(); | ||
expect(context.options.callbacks.onHit).to.be.a.spy.and.to.not.have.been.called(); | ||
expect(context.options.callbacks.onMiss).to.be.a.spy.and.to.have.been.called(); | ||
expect(context.options.callbacks.onError).to.be.a.spy.and.to.have.been.called(); | ||
expect(context.options.callbacks.onAttempt).to.be.a.spy.and.to.have.been.called(); | ||
}); | ||
@@ -273,2 +365,7 @@ }); | ||
expect(context.next).to.be.a.spy.and.to.have.been.called(); | ||
expect(context.options.callbacks.onHit).to.be.a.spy.and.to.not.have.been.called(); | ||
expect(context.options.callbacks.onMiss).to.be.a.spy.and.to.have.been.called(); | ||
expect(context.options.callbacks.onError).to.be.a.spy.and.to.have.been.called(); | ||
expect(context.options.callbacks.onAttempt).to.be.a.spy.and.to.have.been.called(); | ||
}); | ||
@@ -297,2 +394,7 @@ }); | ||
expect(context.next).to.be.a.spy.and.to.have.been.called(); | ||
expect(context.options.callbacks.onHit).to.be.a.spy.and.to.not.have.been.called(); | ||
expect(context.options.callbacks.onMiss).to.be.a.spy.and.to.have.been.called(); | ||
expect(context.options.callbacks.onError).to.be.a.spy.and.to.not.have.been.called(); | ||
expect(context.options.callbacks.onAttempt).to.be.a.spy.and.to.have.been.called(); | ||
}); | ||
@@ -324,2 +426,7 @@ }); | ||
expect(context.next).to.be.a.spy.and.to.not.have.been.called(); | ||
expect(context.options.callbacks.onHit).to.be.a.spy.and.to.have.been.called(); | ||
expect(context.options.callbacks.onMiss).to.be.a.spy.and.to.not.have.been.called(); | ||
expect(context.options.callbacks.onError).to.be.a.spy.and.to.not.have.been.called(); | ||
expect(context.options.callbacks.onAttempt).to.be.a.spy.and.to.have.been.called(); | ||
}); | ||
@@ -351,2 +458,7 @@ }); | ||
expect(context.next).to.be.a.spy.and.to.not.have.been.called(); | ||
expect(context.options.callbacks.onHit).to.be.a.spy.and.to.have.been.called(); | ||
expect(context.options.callbacks.onMiss).to.be.a.spy.and.to.not.have.been.called(); | ||
expect(context.options.callbacks.onError).to.be.a.spy.and.to.not.have.been.called(); | ||
expect(context.options.callbacks.onAttempt).to.be.a.spy.and.to.have.been.called(); | ||
}); | ||
@@ -353,0 +465,0 @@ }); |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
49001
863
61