You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

README.md 7.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. # cacheable-request
  2. > Wrap native HTTP requests with RFC compliant cache support
  3. [![Build Status](https://travis-ci.org/lukechilds/cacheable-request.svg?branch=master)](https://travis-ci.org/lukechilds/cacheable-request)
  4. [![Coverage Status](https://coveralls.io/repos/github/lukechilds/cacheable-request/badge.svg?branch=master)](https://coveralls.io/github/lukechilds/cacheable-request?branch=master)
  5. [![npm](https://img.shields.io/npm/dm/cacheable-request.svg)](https://www.npmjs.com/package/cacheable-request)
  6. [![npm](https://img.shields.io/npm/v/cacheable-request.svg)](https://www.npmjs.com/package/cacheable-request)
  7. [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.
  8. **Note:** This is a low level wrapper around the core HTTP modules, it's not a high level request library.
  9. ## Features
  10. - Only stores cacheable responses as defined by RFC 7234
  11. - Fresh cache entries are served directly from cache
  12. - Stale cache entries are revalidated with `If-None-Match`/`If-Modified-Since` headers
  13. - 304 responses from revalidation requests use cached body
  14. - Updates `Age` header on cached responses
  15. - Can completely bypass cache on a per request basis
  16. - In memory cache by default
  17. - Official support for Redis, MongoDB, SQLite, PostgreSQL and MySQL storage adapters
  18. - Easily plug in your own or third-party storage adapters
  19. - If DB connection fails, cache is automatically bypassed ([disabled by default](#optsautomaticfailover))
  20. - Adds cache support to any existing HTTP code with minimal changes
  21. - Uses [http-cache-semantics](https://github.com/pornel/http-cache-semantics) internally for HTTP RFC 7234 compliance
  22. ## Install
  23. ```shell
  24. npm install --save cacheable-request
  25. ```
  26. ## Usage
  27. ```js
  28. const http = require('http');
  29. const CacheableRequest = require('cacheable-request');
  30. // Then instead of
  31. const req = http.request('http://example.com', cb);
  32. req.end();
  33. // You can do
  34. const cacheableRequest = new CacheableRequest(http.request);
  35. const cacheReq = cacheableRequest('http://example.com', cb);
  36. cacheReq.on('request', req => req.end());
  37. // Future requests to 'example.com' will be returned from cache if still valid
  38. // You pass in any other http.request API compatible method to be wrapped with cache support:
  39. const cacheableRequest = new CacheableRequest(https.request);
  40. const cacheableRequest = new CacheableRequest(electron.net);
  41. ```
  42. ## Storage Adapters
  43. `cacheable-request` uses [Keyv](https://github.com/lukechilds/keyv) to support a wide range of storage adapters.
  44. For example, to use Redis as a cache backend, you just need to install the official Redis Keyv storage adapter:
  45. ```
  46. npm install --save @keyv/redis
  47. ```
  48. And then you can pass `CacheableRequest` your connection string:
  49. ```js
  50. const cacheableRequest = new CacheableRequest(http.request, 'redis://user:pass@localhost:6379');
  51. ```
  52. [View all official Keyv storage adapters.](https://github.com/lukechilds/keyv#official-storage-adapters)
  53. Keyv also supports anything that follows the Map API so it's easy to write your own storage adapter or use a third-party solution.
  54. e.g The following are all valid storage adapters
  55. ```js
  56. const storageAdapter = new Map();
  57. // or
  58. const storageAdapter = require('./my-storage-adapter');
  59. // or
  60. const QuickLRU = require('quick-lru');
  61. const storageAdapter = new QuickLRU({ maxSize: 1000 });
  62. const cacheableRequest = new CacheableRequest(http.request, storageAdapter);
  63. ```
  64. View the [Keyv docs](https://github.com/lukechilds/keyv) for more information on how to use storage adapters.
  65. ## API
  66. ### new cacheableRequest(request, [storageAdapter])
  67. Returns the provided request function wrapped with cache support.
  68. #### request
  69. Type: `function`
  70. Request 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.
  71. #### storageAdapter
  72. Type: `Keyv storage adapter`<br>
  73. Default: `new Map()`
  74. A [Keyv](https://github.com/lukechilds/keyv) storage adapter instance, or connection string if using with an official Keyv storage adapter.
  75. ### Instance
  76. #### cacheableRequest(opts, [cb])
  77. Returns an event emitter.
  78. ##### opts
  79. Type: `object`, `string`
  80. Any of the default request functions options plus:
  81. ###### opts.cache
  82. Type: `boolean`<br>
  83. Default: `true`
  84. If the cache should be used. Setting this to false will completely bypass the cache for the current request.
  85. ###### opts.strictTtl
  86. Type: `boolean`<br>
  87. Default: `false`
  88. If set to `false`, 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.
  89. If set to `true` once a cached resource has expired it is deleted and will have to be re-requested.
  90. ###### opts.automaticFailover
  91. Type: `boolean`<br>
  92. Default: `false`
  93. When 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.
  94. ##### cb
  95. Type: `function`
  96. The callback function which will receive the response as an argument.
  97. The 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.
  98. ##### .on('request', request)
  99. `request` event to get the request object of the request.
  100. **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.
  101. ##### .on('response', response)
  102. `response` event to get the response object from the HTTP request or cache.
  103. ##### .on('error', error)
  104. `error` event emitted in case of an error with the cache.
  105. Errors 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.
  106. To properly handle all error scenarios you should use the following pattern:
  107. ```js
  108. cacheableRequest('example.com', cb)
  109. .on('error', err => {
  110. if (err instanceof CacheableRequest.CacheError) {
  111. handleCacheError(err); // Cache error
  112. } else if (err instanceof CacheableRequest.RequestError) {
  113. handleRequestError(err); // Request function thrown
  114. }
  115. })
  116. .on('request', req => {
  117. req.on('error', handleRequestError); // Request error emitted
  118. req.end();
  119. });
  120. ```
  121. **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.
  122. ## License
  123. MIT © Luke Childs