|
1 | 1 | # http-cache-middleware
|
2 |
| -HTTP Cache Middleware |
| 2 | +High performance connect-like HTTP cache middleware for Node.js. |
| 3 | + |
| 4 | +> Uses `cache-manager` as caching layer, so multiple |
| 5 | +storage engines are supported, i.e: Memory, Redis, ... https://www.npmjs.com/package/cache-manager |
| 6 | + |
| 7 | +## Install |
| 8 | +```js |
| 9 | +npm i http-cache-middleware |
| 10 | +``` |
| 11 | + |
| 12 | +## Usage |
| 13 | +```js |
| 14 | +const middleware = require('http-cache-middleware')() |
| 15 | +const service = require('restana')() |
| 16 | +service.use(middleware) |
| 17 | + |
| 18 | +service.get('/cache-on-get', (req, res) => { |
| 19 | + setTimeout(() => { |
| 20 | + // keep response in cache for 1 minute if not expired before |
| 21 | + res.setHeader('x-cache-timeout', '1 minute') |
| 22 | + res.send('this supposed to be a cacheable response') |
| 23 | + }, 50) |
| 24 | +}) |
| 25 | + |
| 26 | +service.delete('/cache', (req, res) => { |
| 27 | + // ... the logic here changes the cache state |
| 28 | + |
| 29 | + // expire the cache keys using pattern |
| 30 | + res.setHeader('x-cache-expire', '*/cache-on-get') |
| 31 | + res.end() |
| 32 | +}) |
| 33 | + |
| 34 | +service.start(3000) |
| 35 | +``` |
| 36 | +## Redis cache |
| 37 | +```js |
| 38 | +// redis setup |
| 39 | +const CacheManager = require('cache-manager') |
| 40 | +const redisStore = require('cache-manager-ioredis') |
| 41 | +const redisCache = CacheManager.caching({ |
| 42 | + store: redisStore, |
| 43 | + db: 0, |
| 44 | + host: 'localhost', |
| 45 | + port: 6379, |
| 46 | + ttl: 30 |
| 47 | +}) |
| 48 | + |
| 49 | +// middleware instance |
| 50 | +const middleware = require('http-cache-middleware')({ |
| 51 | + stores: [redisCache] |
| 52 | +}) |
| 53 | +``` |
| 54 | + |
| 55 | +## Why cache? |
| 56 | +> Because caching is the last mile for low latency distributed systems! |
| 57 | +
|
| 58 | +Enabling proper caching strategies will drastically reduce the latency of your system, as it reduces network round-trips, database calls and CPU processing. |
| 59 | +For our services, we are talking here about improvements in response times from `X ms` to `~2ms`, as an example. |
| 60 | + |
| 61 | +### Enabling cache for service endpoints |
| 62 | +Enabling a response to be cached just requires the |
| 63 | +`x-cache-timeout` header to be set: |
| 64 | +```js |
| 65 | +res.setHeader('x-cache-timeout', '1 hour') |
| 66 | +``` |
| 67 | +> Here we use the [`ms`](`https://www.npmjs.com/package/ms`) package to convert timeout to seconds. Please note that `millisecond` unit is not supported! |
| 68 | +
|
| 69 | +Example on service using `restana`: |
| 70 | +```js |
| 71 | +service.get('/numbers', (req, res) => { |
| 72 | + res.setHeader('x-cache-timeout', '1 hour') |
| 73 | + |
| 74 | + res.send([ |
| 75 | + 1, 2, 3 |
| 76 | + ]) |
| 77 | +}) |
| 78 | +``` |
| 79 | + |
| 80 | +### Invalidating caches |
| 81 | +Services can easily expire cache entries on demand, i.e: when the data state changes. Here we use the `x-cache-expire` header to indicate the cache entries to expire using a matching pattern: |
| 82 | +```js |
| 83 | +res.setHeader('x-cache-expire', '*/numbers') |
| 84 | +``` |
| 85 | +> Here we use the [`matcher`](`https://www.npmjs.com/package/matcher`) package for matching patterns evaluation. |
| 86 | +
|
| 87 | +Example on service using `restana`: |
| 88 | +```js |
| 89 | +service.patch('/numbers', (req, res) => { |
| 90 | + // ... |
| 91 | + |
| 92 | + res.setHeader('x-cache-expire', '*/numbers') |
| 93 | + res.send(200) |
| 94 | +}) |
| 95 | +``` |
| 96 | + |
| 97 | +### Custom cache keys |
| 98 | +Cache keys are generated using: `req.method + req.url`, however, for indexing/segmenting requirements it makes sense to allow cache keys extensions. |
| 99 | + |
| 100 | +For doing this, we simply recommend using middlewares to extend the keys before caching checks happen: |
| 101 | +```js |
| 102 | +service.use((req, res, next) => { |
| 103 | + req.cacheAppendKey = (req) => req.user.id // here cache key will be: req.method + req.url + req.user.id |
| 104 | + return next() |
| 105 | +}) |
| 106 | +``` |
| 107 | +> In this example we also distinguish cache entries by `user.id`, very important for authorization reasons. |
| 108 | +
|
| 109 | +### Disable cache for custom endpoints |
| 110 | +You can also disable cache checks for certain requests programmatically: |
| 111 | +```js |
| 112 | +service.use((req, res, next) => { |
| 113 | + req.cacheDisabled = true |
| 114 | + return next() |
| 115 | +}) |
| 116 | +``` |
| 117 | + |
| 118 | +## Want to contribute? |
| 119 | +This is your repo ;) |
| 120 | + |
| 121 | +> Note: We aim to be 100% code coverage, please consider it on your pull requests. |
| 122 | +
|
| 123 | +## Related projects |
| 124 | +- fast-gateway (https://www.npmjs.com/package/fast-gateway) |
0 commit comments