Last active
July 26, 2020 09:00
-
-
Save Livin21/744f8c3f84b74e6f187f60a71641dc29 to your computer and use it in GitHub Desktop.
A redis cache middleware written for express
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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