UNPKG

7.59 kBMarkdownView Raw
1# cacheable-request
2
3> Wrap native HTTP requests with RFC compliant cache support
4
5[![Build Status](https://travis-ci.org/lukechilds/cacheable-request.svg?branch=master)](https://travis-ci.org/lukechilds/cacheable-request)
6[![Coverage Status](https://coveralls.io/repos/github/lukechilds/cacheable-request/badge.svg?branch=master)](https://coveralls.io/github/lukechilds/cacheable-request?branch=master)
7[![npm](https://img.shields.io/npm/dm/cacheable-request.svg)](https://www.npmjs.com/package/cacheable-request)
8[![npm](https://img.shields.io/npm/v/cacheable-request.svg)](https://www.npmjs.com/package/cacheable-request)
9
10[RFC 7234](http://httpwg.org/specs/rfc7234.html) compliant HTTP caching for native Node.js HTTP/HTTPS requests. Caching works out of the box in memory or is easily pluggable with a wide range of storage adapters.
11
12**Note:** This is a low level wrapper around the core HTTP modules, it's not a high level request library.
13
14## Features
15
16- Only stores cacheable responses as defined by RFC 7234
17- Fresh cache entries are served directly from cache
18- Stale cache entries are revalidated with `If-None-Match`/`If-Modified-Since` headers
19- 304 responses from revalidation requests use cached body
20- Updates `Age` header on cached responses
21- Can completely bypass cache on a per request basis
22- In memory cache by default
23- Official support for Redis, MongoDB, SQLite, PostgreSQL and MySQL storage adapters
24- Easily plug in your own or third-party storage adapters
25- If DB connection fails, cache is automatically bypassed ([disabled by default](#optsautomaticfailover))
26- Adds cache support to any existing HTTP code with minimal changes
27- Uses [http-cache-semantics](https://github.com/pornel/http-cache-semantics) internally for HTTP RFC 7234 compliance
28
29## Install
30
31```shell
32npm install cacheable-request
33```
34
35## Usage
36
37```js
38const http = require('http');
39const CacheableRequest = require('cacheable-request');
40
41// Then instead of
42const req = http.request('http://example.com', cb);
43req.end();
44
45// You can do
46const cacheableRequest = new CacheableRequest(http.request);
47const cacheReq = cacheableRequest('http://example.com', cb);
48cacheReq.on('request', req => req.end());
49// Future requests to 'example.com' will be returned from cache if still valid
50
51// You pass in any other http.request API compatible method to be wrapped with cache support:
52const cacheableRequest = new CacheableRequest(https.request);
53const cacheableRequest = new CacheableRequest(electron.net);
54```
55
56## Storage Adapters
57
58`cacheable-request` uses [Keyv](https://github.com/lukechilds/keyv) to support a wide range of storage adapters.
59
60For example, to use Redis as a cache backend, you just need to install the official Redis Keyv storage adapter:
61
62```
63npm install @keyv/redis
64```
65
66And then you can pass `CacheableRequest` your connection string:
67
68```js
69const cacheableRequest = new CacheableRequest(http.request, 'redis://user:pass@localhost:6379');
70```
71
72[View all official Keyv storage adapters.](https://github.com/lukechilds/keyv#official-storage-adapters)
73
74Keyv also supports anything that follows the Map API so it's easy to write your own storage adapter or use a third-party solution.
75
76e.g The following are all valid storage adapters
77
78```js
79const storageAdapter = new Map();
80// or
81const storageAdapter = require('./my-storage-adapter');
82// or
83const QuickLRU = require('quick-lru');
84const storageAdapter = new QuickLRU({ maxSize: 1000 });
85
86const cacheableRequest = new CacheableRequest(http.request, storageAdapter);
87```
88
89View the [Keyv docs](https://github.com/lukechilds/keyv) for more information on how to use storage adapters.
90
91## API
92
93### new cacheableRequest(request, [storageAdapter])
94
95Returns the provided request function wrapped with cache support.
96
97#### request
98
99Type: `function`
100
101Request function to wrap with cache support. Should be [`http.request`](https://nodejs.org/api/http.html#http_http_request_options_callback) or a similar API compatible request function.
102
103#### storageAdapter
104
105Type: `Keyv storage adapter`<br>
106Default: `new Map()`
107
108A [Keyv](https://github.com/lukechilds/keyv) storage adapter instance, or connection string if using with an official Keyv storage adapter.
109
110### Instance
111
112#### cacheableRequest(opts, [cb])
113
114Returns an event emitter.
115
116##### opts
117
118Type: `object`, `string`
119
120- Any of the default request functions options.
121- Any [`http-cache-semantics`](https://github.com/kornelski/http-cache-semantics#constructor-options) options.
122- Any of the following:
123
124###### opts.cache
125
126Type: `boolean`<br>
127Default: `true`
128
129If the cache should be used. Setting this to false will completely bypass the cache for the current request.
130
131###### opts.strictTtl
132
133Type: `boolean`<br>
134Default: `false`
135
136If set to `true` once a cached resource has expired it is deleted and will have to be re-requested.
137
138If set to `false` (default), after a cached resource's TTL expires it is kept in the cache and will be revalidated on the next request with `If-None-Match`/`If-Modified-Since` headers.
139
140###### opts.maxTtl
141
142Type: `number`<br>
143Default: `undefined`
144
145Limits TTL. The `number` represents milliseconds.
146
147###### opts.automaticFailover
148
149Type: `boolean`<br>
150Default: `false`
151
152When set to `true`, if the DB connection fails we will automatically fallback to a network request. DB errors will still be emitted to notify you of the problem even though the request callback may succeed.
153
154###### opts.forceRefresh
155
156Type: `boolean`<br>
157Default: `false`
158
159Forces refreshing the cache. If the response could be retrieved from the cache, it will perform a new request and override the cache instead.
160
161##### cb
162
163Type: `function`
164
165The callback function which will receive the response as an argument.
166
167The response can be either a [Node.js HTTP response stream](https://nodejs.org/api/http.html#http_class_http_incomingmessage) or a [responselike object](https://github.com/lukechilds/responselike). The response will also have a `fromCache` property set with a boolean value.
168
169##### .on('request', request)
170
171`request` event to get the request object of the request.
172
173**Note:** This event will only fire if an HTTP request is actually made, not when a response is retrieved from cache. However, you should always handle the `request` event to end the request and handle any potential request errors.
174
175##### .on('response', response)
176
177`response` event to get the response object from the HTTP request or cache.
178
179##### .on('error', error)
180
181`error` event emitted in case of an error with the cache.
182
183Errors emitted here will be an instance of `CacheableRequest.RequestError` or `CacheableRequest.CacheError`. You will only ever receive a `RequestError` if the request function throws (normally caused by invalid user input). Normal request errors should be handled inside the `request` event.
184
185To properly handle all error scenarios you should use the following pattern:
186
187```js
188cacheableRequest('example.com', cb)
189 .on('error', err => {
190 if (err instanceof CacheableRequest.CacheError) {
191 handleCacheError(err); // Cache error
192 } else if (err instanceof CacheableRequest.RequestError) {
193 handleRequestError(err); // Request function thrown
194 }
195 })
196 .on('request', req => {
197 req.on('error', handleRequestError); // Request error emitted
198 req.end();
199 });
200```
201
202**Note:** Database connection errors are emitted here, however `cacheable-request` will attempt to re-request the resource and bypass the cache on a connection error. Therefore a database connection error doesn't necessarily mean the request won't be fulfilled.
203
204## License
205
206MIT © Luke Childs