Skip to content

Instantly share code, notes, and snippets.

@Livin21
Last active July 26, 2020 09:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Livin21/744f8c3f84b74e6f187f60a71641dc29 to your computer and use it in GitHub Desktop.
Save Livin21/744f8c3f84b74e6f187f60a71641dc29 to your computer and use it in GitHub Desktop.
A redis cache middleware written for express
/**
* Copyright (c) 2020
* A redis cache middleware written for express
* If the cache middleware is hooked to the express route
* - Checks if request response was cached
* - Redis key is SHA256 of req.originalUrl
* - if cache hit, sends cached data
* - if cache miss, calls next()
* - The second middleware listens for req.send event and caches res.body for 200 status
* Usage:
* const { cacheRoute } = require("../utils/cacheStore");
* router.get('/all/:page', ...cacheRoute(), (req, res) => {});
*
* @summary Redis cache middleware written for express
* @author Livin Mathew <livinmathew99@gmail.com>
*/
const CachemanRedis = require('cacheman-redis');
const cache = new CachemanRedis();
const crypto = require("crypto");
const mung = require('express-mung');
// Default cache expiry set to 1 hour (3600 seconds)
const cacheExpiry = 3600;
// Set cache by key
function setCache(key, value, expiry = cacheExpiry) {
const promise = new Promise((resolve, reject) => {
cache.set(key, value, expiry, (err) => {
if (err) return reject(err);
resolve();
console.info(`Cached ${key}`);
});
});
return promise;
}
// Get cache by key
function getCache(key) {
const promise = new Promise((resolve) => {
cache.get(key, (err, value) => {
if (err) {
console.error(err);
}
resolve(value);
console.info(`Cache ${value ? "hit" : "miss"} for ${key}`);
});
});
return promise;
}
// Clear cache by key. Flushes entire cache if key is not provided
function clearCache(key) {
const promise = new Promise((resolve, reject) => {
if (key) {
cache.del(key, (err) => {
if (err) return reject(err);
resolve();
console.info(`Cleared ${key} cache`);
});
} else {
cache.clear((err) => {
if (err) return reject(err);
resolve();
console.info("Cache flushed!");
});
}
});
return promise;
}
module.exports = {
setCache,
getCache,
clearCache,
cacheRoute(expiry = cacheExpiry, optionalKey) {
return [
// A middleware that checks and returns cached value
async (req, res, next) => {
const key = optionalKey ?? crypto.createHash('sha256').update(req.originalUrl).digest("hex");
req.cacheKey = key;
const cachedValue = await getCache(key);
if (cachedValue) {
return res.send(cachedValue);
}
req.cacheMissed = true;
next();
},
// A listener middleware that caches while response being sent
mung.json((body, req, res) => {
if(req.cacheMissed && res.statusCode === 200){
setCache(req.cacheKey, body, expiry);
}
}),
];
},
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment