diff --git a/README.md b/README.md index df3ed92..06737ee 100644 --- a/README.md +++ b/README.md @@ -64,24 +64,20 @@ const onionoo = new Onionoo({ 'clients', 'uptime' ], - cache: { - store: 'memory', - ttl: 18000, - max: 500 - } + cache: false }); ``` -## Cache Stores +## Cache -This module makes use of [`node-cache-manager`](https://github.com/BryanDonovan/node-cache-manager) to support multiple cache stores. By default cached responses are stored in memory. You can easily disable the cache or use a more scalable cache store such as Redis by using `node-cache-manager`'s [store engine](https://github.com/BryanDonovan/node-cache-manager#store-engines) modules. +By default no cache is used. You can easily cache in memory or to a more scaleable store like Redis using [Keyv storage adapters](https://github.com/lukechilds/keyv#official-storage-adapters). -Disable cache: +Cache in memory: ```js const Onionoo = require('onionoo'); const onionoo = new Onionoo({ - cache: false + cache: new Map() }); ``` @@ -89,11 +85,12 @@ Use persistent Redis cache: ```js const Onionoo = require('onionoo'); -const redisStore = require('cache-manager-redis'); +const KeyvRedis = require('@keyv/redis'); + +const redis = new KeyvRedis('redis://user:pass@localhost:6379'); + const onionoo = new Onionoo({ - cache: { - store: redisStore - } + cache: redis }); ``` @@ -123,10 +120,10 @@ Array of endpoints to be returned as methods on the `Onionoo` instance. ##### options.cache -Type: `object`, `boolean`
-Default: `{ store: 'memory', ttl: 18000, max: 500 }` +Type: `object`
+Default: `false` -Options object to be merged with default options and passed to [`node-cache-manager`](https://github.com/BryanDonovan/node-cache-manager). Alternatively, if set to false, caching will be disabled. +[Keyv](https://github.com/lukechilds/keyv) storage adapter instance for storing cached data. ### onionoo.endpoint([query]) diff --git a/package.json b/package.json index 8ef9bc6..b591ff5 100644 --- a/package.json +++ b/package.json @@ -26,16 +26,11 @@ }, "homepage": "https://github.com/lukechilds/onionoo-node-client", "dependencies": { - "cache-manager": "2.5.0", - "deep-assign": "2.0.0", - "expired": "1.3.12", "got": "8.0.0" }, "devDependencies": { "ava": "^0.24.0", "coveralls": "^3.0.0", - "date-fns": "^1.21.1", - "delay": "^2.0.0", "nock": "^9.0.2", "nyc": "^11.0.0", "xo": "^0.19.0" diff --git a/src/index.js b/src/index.js index d35720a..5867c64 100644 --- a/src/index.js +++ b/src/index.js @@ -1,8 +1,5 @@ const querystring = require('querystring'); const got = require('got'); -const cacheManager = require('cache-manager'); -const expired = require('expired'); -const deepAssign = require('deep-assign'); const pkg = require('../package.json'); class Onionoo { @@ -21,13 +18,6 @@ class Onionoo { 'uptime' ] }, options); - if (options.cache !== false) { - this.options.cache = cacheManager.caching(Object.assign({ - store: 'memory', - ttl: 18000, // 5 hours - max: 500 - }, options.cache)); - } // Return object containing endpoint methods return this.options.endpoints.reduce((onionoo, endpoint) => { @@ -46,75 +36,14 @@ class Onionoo { let url = `${this.options.baseUrl}/${endpoint}`; url += qs ? `?${qs}` : ''; - // If caching is disabled, just make the request - if (!this.options.cache) { - return this.makeRequest(url); - } - - // If caching is enabled, check for url in cache - return this.options.cache.get(url) - .then(cachedResult => { - const options = {}; - - // If we have it cached - if (cachedResult) { - // Return the cached entry if it's still valid - if (!expired(cachedResult.headers)) { - return cachedResult; - - // If it's stale, add last-modified date to headers - } else if (cachedResult.headers['last-modified']) { - options.headers = { - 'if-modified-since': cachedResult.headers['last-modified'] - }; - } - } - - // Make a request - return this.makeRequest(url, options) - .then(response => { - // If we get a 304, fill in the body - if (response.statusCode === 304) { - response.body = cachedResult.body; - } - - // If we get a 200 or 304, cache it - if ([200, 304].includes(response.statusCode)) { - this.options.cache.set(url, response); - } - - return response; - }); - }); - } - - // Returns a promise for a request - makeRequest(url, options = {}) { - options = deepAssign({ + // Make request + return got(url, { headers: { 'user-agent': `onionoo-node-client v${pkg.version} (${pkg.homepage})` - } - }, options); - - return got(url, options) - .catch(err => { - // Don't throw 304 responses - if (err.statusCode === 304) { - return err.response; - } - throw err; - }) - .then(response => { - // Format response - response = { - statusCode: response.statusCode, - statusMessage: response.statusMessage, - headers: response.headers, - body: response.body && JSON.parse(response.body) - }; - - return response; - }); + }, + json: true, + cache: this.options.cache + }); } } diff --git a/test/cache.js b/test/cache.js index 6d252da..baf33d5 100644 --- a/test/cache.js +++ b/test/cache.js @@ -1,12 +1,10 @@ import test from 'ava'; import nock from 'nock'; -import subSeconds from 'date-fns/sub_seconds'; -import delay from 'delay'; import Onionoo from '../'; import data from './fixtures/data'; -test('Cache can be disabled', async t => { - const onionoo = new Onionoo({cache: false}); +test('Cache is disabled by default', async t => { + const onionoo = new Onionoo(); const defaultEndpoint = data.defaultEndpoints[0]; const responseHeaders = { @@ -21,7 +19,7 @@ test('Cache can be disabled', async t => { const response = await onionoo[defaultEndpoint](); - t.deepEqual(response.body, data.dummyResponse); + t.false(response.fromCache); t.truthy(scope.isDone()); const scope2 = nock(data.defaultBaseUrl) @@ -30,12 +28,12 @@ test('Cache can be disabled', async t => { const response2 = await onionoo[defaultEndpoint](); - t.deepEqual(response2.body, data.dummyResponse); + t.false(response2.fromCache); t.truthy(scope2.isDone()); }); -test('Responses with future max-age are cached', async t => { - const onionoo = new Onionoo(); +test('Cache options is passed through to Got', async t => { + const onionoo = new Onionoo({cache: new Map()}); const defaultEndpoint = data.defaultEndpoints[0]; const responseHeaders = { @@ -50,84 +48,10 @@ test('Responses with future max-age are cached', async t => { const response = await onionoo[defaultEndpoint](); - t.deepEqual(response.body, data.dummyResponse); + t.false(response.fromCache); t.truthy(scope.isDone()); - const cachedResponse = await onionoo[defaultEndpoint](); - - t.deepEqual(cachedResponse.body, data.dummyResponse); -}); - -test('Responses older than max-age are not cached', async t => { - const onionoo = new Onionoo(); - - const defaultEndpoint = data.defaultEndpoints[0]; - const responseHeaders = { - date: subSeconds(new Date(), 15).toUTCString(), - age: 0, - 'cache-control': 'public, max-age=10' - }; - - const scope = nock(data.defaultBaseUrl) - .get(`/${defaultEndpoint}`) - .reply(200, data.dummyResponse, responseHeaders); - - const response = await onionoo[defaultEndpoint](); - - t.deepEqual(response.body, data.dummyResponse); - t.truthy(scope.isDone()); - - const scope2 = nock(data.defaultBaseUrl) - .get(`/${defaultEndpoint}`) - .reply(200, data.dummyResponse, responseHeaders); - const response2 = await onionoo[defaultEndpoint](); - t.deepEqual(response2.body, data.dummyResponse); - t.truthy(scope2.isDone()); -}); - -test('When expired, add last-modified date to headers and handle 304', async t => { - const onionoo = new Onionoo(); - - const defaultEndpoint = data.defaultEndpoints[0]; - const initialDate = new Date().toUTCString(); - const responseHeaders = { - date: initialDate, - age: 0, - 'cache-control': 'public, max-age=1', - 'last-modified': initialDate - }; - - const scope = nock(data.defaultBaseUrl) - .get(`/${defaultEndpoint}`) - .reply(200, data.dummyResponse, responseHeaders); - - const response = await onionoo[defaultEndpoint](); - - t.deepEqual(response.body, data.dummyResponse); - t.truthy(scope.isDone()); - - const requestHeaders = { - 'if-modified-since': initialDate - }; - const responseHeaders304 = { - date: new Date().toUTCString(), - age: 0, - 'cache-control': 'public, max-age=10', - 'last-modified': initialDate - }; - - const scope2 = nock(data.defaultBaseUrl, {requestHeaders}) - .get(`/${defaultEndpoint}`) - .reply(304, null, responseHeaders304); - - const response2 = await delay(2000).then(onionoo[defaultEndpoint]); - - t.deepEqual(response2.body, data.dummyResponse); - t.truthy(scope2.isDone()); - - const cachedResponse = await onionoo[defaultEndpoint](); - - t.deepEqual(cachedResponse.body, data.dummyResponse); + t.true(response2.fromCache); });