# @bbc/http-transport-cache

> Caching middleware

Latest version **5.0.0** (published 2024-12-06) · Apache-2.0 license · 1.2K weekly downloads

## Install

```sh
npm install @bbc/http-transport-cache
pnpm add @bbc/http-transport-cache
yarn add @bbc/http-transport-cache
bun add @bbc/http-transport-cache
```

## Health

**Score 45/100 (D)** — status: stable.

Positive: no vulnerabilities.

Warnings: no types; no esm support.

Negative: stale.

## Facts

| | |
|---|---|
| Version | 5.0.0 |
| Published | 2024-12-06 |
| First published | 2017-09-05 |
| Weekly downloads | 1.2K |
| License | Apache-2.0 |
| TypeScript types | none |
| Module format | CommonJS |
| Node | >=8.13.0 |
| Dependencies | 5 |
| Unpacked size | 71.8 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 4 |
| Maintainers | mknish, sbason, abz.me, catherine_hpr, henrywarne, caporp01, swatitabib, ianarundale, milkywaynian, andycharris, carrejoe3, hafsa-abdulsalim, chibbc, lexedwardsbbc, ajitsanto09, tmoco, yusuf963m, anthonygreen, rsblandamer, tzaman76, lukeparker02, ramkup01, aggari01, rlfbbc, singhn08, jamesdesq, shahp07, roopashree-ramachandraiah, hjerling, mstephensonbbc, bhartn01, ibl, kieranjoyce, pjlangley, szpytfire-bbc, simontanner, simongregory, tonymcbeth, johnnewman, drrobharper, jamiebower185, benjwheeler, onlyonehas, gingertonicst, iuketaylor, monsai, notten13, vaughr03, npmbs, brotherkaif, naivinh.ta.bbc, alexshelley, oliviadrury, pshaw03, chriss901, david.toluhi, amitsavant, eobr, cjewell47, vinodrane, dwalker487, katyasa, felixmercermoss, rosemcnally, gozcue01-bbc |
| Keywords | http-transport, caching, http, client, middleware |

## Links

- npm: https://www.npmjs.com/package/@bbc/http-transport-cache
- Repository: https://github.com/bbc/http-transport-cache
- Homepage: https://github.com/bbc/http-transport-cache#readme
- Issues: https://github.com/bbc/http-transport-cache/issues
- npm.io page: https://npm.io/package/@bbc/http-transport-cache

## Dependencies (5)

- [lodash](https://npm.io/package/lodash.md) ^4.17.20
- [bluebird](https://npm.io/package/bluebird.md) ^3.7.2
- [@hapi/wreck](https://npm.io/package/@hapi/wreck.md) ^18.0.1
- [@hapi/catbox](https://npm.io/package/@hapi/catbox.md) ^12.1.1
- [@hapi/catbox-memory](https://npm.io/package/@hapi/catbox-memory.md) ^6.0.1

## Alternatives

- [launchdarkly-js-client-sdk](https://npm.io/package/launchdarkly-js-client-sdk.md) — 2.5M weekly downloads
- [@elastic/elasticsearch](https://npm.io/package/@elastic/elasticsearch.md) — 2.1M weekly downloads
- [@c8y/client](https://npm.io/package/@c8y/client.md) — 15.3K weekly downloads
- [@signaldb/maverickjs](https://npm.io/package/@signaldb/maverickjs.md) — 1.7K weekly downloads
- [@saptools/cf-live-trace](https://npm.io/package/@saptools/cf-live-trace.md) — 693 weekly downloads

## Recent versions

- 5.0.0 (latest) — 2024-12-06
- 1.3.8 (beta-swr) — 2018-01-17
- 4.4.0 — 2024-10-15
- 4.3.1 — 2024-02-09
- 4.3.0 — 2023-11-20
- 4.2.2 — 2023-09-29
- 4.2.1 — 2023-09-29
- 4.2.0 — 2023-09-28
- 4.1.0 — 2022-08-22
- 4.0.3 — 2022-08-02
- 4.0.2 — 2020-09-24
- 4.0.1 — 2020-09-24
- 4.0.0 — 2020-09-08
- 3.11.0 — 2020-09-07
- 3.10.0 — 2020-02-11
- … 42 more at https://npm.io/package/@bbc/http-transport-cache/versions

## README

[![NPM downloads](https://img.shields.io/npm/dm/@bbc/http-transport-cache.svg?style=flat)](https://npmjs.org/package/@bbc/http-transport-cache)
![npm](https://img.shields.io/npm/v/@bbc/http-transport-cache.svg)
 ![license](https://img.shields.io/badge/license-MIT-blue.svg) 
![github-issues](https://img.shields.io/github/issues/bbc/http-transport-cache.svg)
![stars](https://img.shields.io/github/stars/bbc/http-transport-cache.svg)
![forks](https://img.shields.io/github/forks/bbc/http-transport-cache.svg)

# HTTP Transport Cache

A HTTP spec compliant caching layer for `http-transport`.

## Installation

```
npm install --save http-transport-cache
```

## Usage

Configure response caching based on max-age:

```js
const cache = require('@bbc/http-transport-cache');
const Catbox = require('@hapi/catbox');
const HttpTransport = require('@bbc/http-transport');

const catbox = new Catbox.Client(new Memory());

const url = 'http://example.com/';

const client = HttpTransport.createBuilder()
      .use(cache.maxAge(catbox))
      .createClient();

      const body = await client.get(url)
        .asBody();

      console.log(body);
```

Configure stale-if-error:

```js
const cache = require('@bbc/http-transport-cache');
const Catbox = require('catbox');
const HttpTransport = require('@bbc/http-transport');

const catbox = new Catbox.Client(new Memory());

const url = 'http://example.com/';

const client = HttpTransport.createClient()
      .use(cache.staleIfError(catbox))
      .createClient();

      const body = await client.get(url)
        .asBody();

      console.log(body);
```

Listening to Events:
``` JS
const { events, maxAge } = require('@bbc/http-transport-cache');

const stats = require('@ibl/stats');
const Catbox = require('catbox');
const HttpTransport = require('@bbc/http-transport');

const catbox = new Catbox.Client(new Memory());

const url = 'http://example.com/';

const client = HttpTransport.createBuilder()
  .use(cache.maxAge(catbox, {
    name: `theservice`,
  }))
  .createClient();

events.on(`cache.theservice.read_time`, (ctx) => {
  stats.timing(`timingstat.read_time`, ctx.duration);
});
```


## Features

|Feature|Description|
|----|-----------|
|Warnings|The cached response only contains the simplified `http-transport` request and response so as not to waste cache space.|
|Max Age|Responses are stored for the duration of the `max-age` directive and are used before any requests are made.|
|Stale If Error|In order to ensure a resilient service even during errors, http responses can include a `cache-control` directive called `stale-if-error` which means we can use a cached response for that period whilst the service is erroring. To do this a separate response blob is stored for the stale period and on error this response is used alongside the body which is stored for the higher of either `max-age` or `stale-if-error`.|
|No Store|If `no-store` directive is present in the response, it will not be stored / cached anywhere.|
|Private|If `private` directive is present in the response, it will not be stored by shared cache. The response will only be stored in a private cache intended for a single user.|


### Events
- hit
- miss
- error 
- timeout 
- stale
- read_time
- write_time
- connection_error

## Middleware Options

Both `maxage` and `staleIfError` accept an options object. 

|Property|type|module|Description|
|----|----|----|-----------|
|`ignoreCacheErrors`|boolean|maxAge,staleIfError| `cache.maxAge` will return a cache miss when this property is `true`. Setting this property true for `cache.staleIfError` will rethrow the original error (not the cache lookup error). `ignoreCacheErrors` is `false` by default.|
|`timeout`|integer|maxAge|Timeouts a cache lookup after a specified number of ms. By default, no timeout is specified.|
|`connectionTimeout`|integer|maxAge,staleIfError|Timeouts the attempt to connect to a cache after a specified number of ms. By default, no timeout is specified.|
|`includeCacheStatusInCtx`|boolean|maxAge,staleIfError| When present, a `cacheStatus` array - recording all cache events, will be set in `context` for use by other plugins. `includeCacheStatusInCtx` is `false` by default.|

## Cache version

The cache verison is stored in the `config.json`, this is distinct from the library version in the `package.json`. The cache version is used in the cache key and is intended to reduce cache fragmentation in a scenario where multiple different versions of this library might be in use across a single estate.

The cache version **must** be incremented if a change is made to the data stored in the cache that would be incompatible with the existing version. Otherwise it should not be changed.

## Cache Key Structure
 
The cache uses `catbox` to provide a simple pluggable interface, this supports segmenting the cache as well as IDs, thus the following segments are used:

* http-transport:{version}:response - Basic response from a call cached for the duration of the `max-age` value key on just the URL of the response.
* http-transport:{version}:staleResponse - Stale response from a called cached for the `stale-if-error` value keyed on just the URL of the response.

Additionally, cache keys can be configured by passing a `varyOn` option. `varyOn` should contain an array of request header names which the cache should additionally vary on; for some use-cases, requests made to the same endpoint but with differing values for certain headers elicit different responses - and therefore cannot share the same cached response e.g.`accept-language`. By letting `http-transport-cache` know which headers to vary on, a unique cache key will be constructed which also contains said headers and their values.

Example:

We make a `GET` request to the following URL: `www.example.com/some-cacheable-path`.

We vary on `accept-language` and `accept`. These headers will exist in the request. We pass in `varyOn` (an array of request headers we vary on) together with other options to configure the plugin.

```js
const opts = {
  timeout: 2000,
  varyOn: [
    'accept-language',
    'accept'
  ]
};
```

On the first request, the value of `accept-language` is `en` and `accept` is `application/json`. The resulting key will be:

* GET:www.example.com/some-cacheable-path:accept-language=en,accept=application/json

On the second request, the value of `accept-language` is `fr` and `accept` is `text/html`. The resulting key will be:

* GET:www.example.com/some-cacheable-path:accept-language=fr,accept=text/html

This way we avoid overwritting data in the store.

## Test

```
npm test
```

To generate a test coverage report:

```
npm run coverage
```

---
_Source: https://npm.io/package/@bbc/http-transport-cache · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
