• Stars
    star
    204
  • Rank 192,063 (Top 4 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created almost 6 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

An HTTP compliant route path middleware for serving cache response with invalidation support.

cacheable-response

Last version Coverage Status NPM Status

An HTTP compliant route path middleware for serving cache response with invalidation support.

Why

Server Side Rendering (SSR) is a luxurious but necessary thing if you want to have a first class user experience.

The main issue of doing server-side things is the extra cost associated with dynamic things: The server will take CPU cycles to compute the value to be served, probably discarded in the next page reload, losing precious resources in the process.

Instead of serving a real timeβ„’ – and costly – response, we can say it is OK serving a pre-calculated response but much much cheaper.

That will save CPU cycles, saving them for things that really matters.

Caching states

Value Description
MISS The resource was looked into the cache but did not find it, so a new copy is generated and placed into the cache.
HIT The resources was found into the cache, being generated by a previous access.
EXPIRED The resouce was found but it is expired, being necessary regerate it.
BYPASS The cache is forced to be bypassed, regenerating the resource.
STALE The resource is expired but it's served while a new cache copy is generated in background.

Install

$ npm install cacheable-response --save

Get Started

cacheable-response is a HTTP middleware for a serving pre-calculated response.

It's like a LRU cache but with all the logic necessary for auto-invalidate response copies and refresh them.

Imagine you are currently running an HTTP microservice to compute something heavy in terms of CPU

const server = ({ req, res }) => {
  const data = doSomething(req)
  res.send(data)
}

To leverage caching capabilities, just you need to adapt your HTTP based project a bit for following cacheable-response interface

const cacheableResponse = require('cacheable-response')

const ssrCache = cacheableResponse({
  get: ({ req, res }) => ({
    data: doSomething(req),
    ttl: 86400000 // 24 hours
  }),
  send: ({ data, res, req }) => res.send(data)
})

At least, cacheable-response needs two things:

  • get: It creates a fresh cacheable response associated with the current route path.
  • send: It determines how the response should be rendered.

cacheable-response is framework agnostic: It could be used with any library that accepts (request, response) as input.

const micro = require('micro')

/* Explicitly pass `cacheable-response` as server */
micro((req, res) => ssrCache({ req, res }))

That's include any express-like framework as well.

const express = require('express')
const app = express()

/* Passing `cacheable-response` instance as middleware */
app.use((req, res) => ssrCache({ req, res }))

See more examples.

At all times the cache status is reflected as x-cache headers in the response.

The first resource access will be a MISS.

HTTP/2 200
cache-control: public, max-age=7200, stale-while-revalidate=300
ETag: "d-pedE0BZFQNM7HX6mFsKPL6l+dUo"
x-cache-status: MISS
x-cache-expired-at: 1h 59m 60s

Successive resource access under the ttl period returns a HIT

HTTP/2 200
cache-control: public, max-age=7170, stale-while-revalidate=298
ETag: "d-pedE0BZFQNM7HX6mFsKPL6l+dUo"
x-cache-status: HIT
x-cache-expired-at: 1h 59m 30s

After ttl period expired, the cache will be invalidated and refreshed in the next request.

In case you need you can force invalidate a cache response passing force=true as part of your query parameters.

curl https://myserver.dev/user # MISS (first access)
curl https://myserver.dev/user # HIT (served from cache)
curl https://myserver.dev/user # HIT (served from cache)
curl https://myserver.dev/user?force=true # BYPASS (skip cache copy)

In that case, the x-cache-status will reflect a 'BYPASS' value.

Additionally, you can configure a stale ttl:

const cacheableResponse = require('cacheable-response')

const ssrCache = cacheableResponse({
  get: ({ req, res }) => ({
    data: doSomething(req),
    ttl: 86400000, // 24 hours
    staleTtl: 3600000 // 1h
  }),
  send: ({ data, res, req }) => res.send(data)
})

The stale ttl maximizes your cache HITs, allowing you to serve a no fresh cache copy while doing revalidation on the background.

curl https://myserver.dev/user # MISS (first access)
curl https://myserver.dev/user # HIT (served from cache)
curl https://myserver.dev/user # STALE (23 hours later, background revalidation)
curl https://myserver.dev/user?force=true # HIT (fresh cache copy for the next 24 hours)

The library provides enough good sensible defaults for most common scenarios and you can tune these values based on your use case.

API

cacheableResponse([options])

options

bypassQueryParameter

Type: string
Default: 'force'

The name of the query parameter to be used for skipping the cache copy in an intentional way.

cache

Type: boolean
Default: new Keyv({ namespace: 'ssr' })

The cache instance used for backed your pre-calculated server side response copies.

The library delegates in keyv, a tiny key value store with multi adapter support.

If you don't specify it, a memory cache will be used.

compress

Type: boolean
Default: false

Enable compress/decompress data using brotli compression format.

get

Required
Type: function

The method to be called for creating a fresh cacheable response associated with the current route path.

async function get ({ req, res }) {
  const data = doSomething(req, res)
  const ttl = 86400000 // 24 hours
  const headers = { userAgent: 'cacheable-response' }
  return { data, ttl, headers }
}

The method will received ({ req, res }) and it should be returns:

  • data object|string: The content to be saved on the cache.
  • ttl number: The quantity of time in milliseconds the content is considered valid on the cache. Don't specify it means use default ttl.
  • createdAt date: The timestamp associated with the content (Date.now() by default).

Any other property can be specified and will passed to .send.

In case you want to bypass the cache, preventing caching a value (e.g., when an error occurred), you should return undefined or null.

key

Type: function
Default: ({ req }) => req.url)

It determinates how the cache key should be computed, receiving req, res as input.

logger

Type: function
Default: () => {}

When it's present, every time cacheable-response is called, a log will be printed.

send

Required
Type: function

The method used to determinate how the content should be rendered.

async function send ({ req, res, data, headers }) {
  res.setHeader('user-agent', headers.userAgent)
  res.send(data)
}

It will receive ({ req, res, data, ...props }) being props any other data supplied to .get.

staleTtl

Type: number|boolean|function
Default: 3600000

Number of milliseconds that indicates grace period after response cache expiration for refreshing it in the background. The latency of the refresh is hidden from the user.

This value can be specified as well providing it as part of .get output.

The value will be associated with stale-while-revalidate directive.

You can pass a false to disable it.

ttl

Type: number|function
Default: 86400000

Number of milliseconds a cache response is considered valid.

After this period of time, the cache response should be refreshed.

This value can be specified as well providing it as part of .get output.

If you don't provide one, this be used as fallback for avoid keep things into cache forever.

serialize

Type: function
Default: JSON.stringify

Set the serializer method to be used before compress.

deserialize

Type: function
Default: JSON.parse

Set the deserialize method to be used after decompress.

Pro-tip: Distributed cache with CloudFlareℒ️

This content is not sponsored; Just I consider CloudFlare is doing a good job offering a cache layer as part of their free tier.

Imagine what could be better than having one cache layer?

Exactly, two cache layers.

If your server domain is connected with CloudFlare you can take advantage of having a distributed CDN that also caches your responses.

For doing that, you need to setup a Page Rule over your domain specifing you want to enable cache. Read more how to do that.

Next time you query about a resource, a new cf-cache-status appeared as part of your headers response.

HTTP/2 200
cache-control: public, max-age=7200, stale-while-revalidate=300
ETag: "d-pedE0BZFQNM7HX6mFsKPL6l+dUo"
x-cache-status: MISS
x-cache-expired-at: 1h 59m 60s
cf-cache-status: MISS

CloudFlare will respect your cache-control policy, creating another caching layer reflected by cf-cache-status

HTTP/2 200
cache-control: public, max-age=7200, stale-while-revalidate=300
ETag: "d-pedE0BZFQNM7HX6mFsKPL6l+dUo"
x-cache-status: MISS
x-cache-expired-at: 1h 59m 60s
cf-cache-status: HIT

Note how in this second request x-cache-status is still a MISS.

That's because CloudFlare way for caching the content includes caching the response headers.

The headers associated with the cache copy will the headers from the first request. You need to look at cf-cache-status instead.

You can have a better overview of the percentage of success by looking your CloudFlare domain analytics

Examples

Make a PR for adding your project!

Bibliography

License

cacheable-response Β© Kiko Beats, released under the MIT License.
Authored and maintained by Kiko Beats with help from contributors.

kikobeats.com Β· GitHub Kiko Beats Β· Twitter @Kikobeats

More Repositories

1

awesome-api

A curated list of awesome resources for design and implement RESTful API's.
2,344
star
2

uno-zen

Minimalist and Elegant theme for Ghost. Demo @ https://kikobeats.com
CSS
872
star
3

js-mythbusters

πŸ‘» STHAP js, where is my perf?
SCSS
630
star
4

awesome-github

An exquisite list of awesome :octocat: secrets.
596
star
5

awesome-network-js

A 🎩 list of network layer resources written pure JS.
541
star
6

awesome-cli

A curated list of awesome resources for building immersive CLI experiences.
207
star
7

tom

tom 🐢 is a backoffice for your projects
JavaScript
138
star
8

react-clap-button

A Medium like clap button
JavaScript
119
star
9

git-authors-cli

It detects project contributors; add contributors into `package.json`
JavaScript
109
star
10

top-user-agents

A list of most common User Agent used on Internet.
JavaScript
96
star
11

awesome-gif

A curated list of awesome gif's resources.
91
star
12

emojis-list

Complete list of standard emojis.
JavaScript
88
star
13

free-email-domains

A comprehensive list of all free email domain providers.
JavaScript
76
star
14

array-future

A collection of Array prototypes prollyfills as proposition for ECMAScript 7.
CoffeeScript
73
star
15

svr

HTTP development server done right
CSS
71
star
16

osom

An Awesome [/osom/] Object Data Modeling (Database Agnostic).
JavaScript
69
star
17

nodengine

Node.js version switcher based on engines at `package.json`.
JavaScript
68
star
18

aws-lambda-chrome

Chrome binary compatible with AWS Lambda.
JavaScript
56
star
19

json-future

Modern JSON interface.
JavaScript
55
star
20

automate-release

No more manual work in your software releases.
HTML
52
star
21

oh-my-terminal

Simple and unmistakable terminal interface for NodeJS.
CoffeeScript
49
star
22

farm-cli

Resilient multi-process architecture from your CLI
JavaScript
49
star
23

to-query

Get query object from a request url
JavaScript
44
star
24

regexgen-cli

CLI interface for regexgen. Generates regular expressions that match a set of strings.
JavaScript
35
star
25

compress-brotli

Simple cross Node.js inteface for using brotli compression
JavaScript
35
star
26

hyperlru

Tiny & Fast LRU Implementation as possible.
JavaScript
34
star
27

http-compression

Adding compression (gzip/brotli) for your HTTP server in Node.js.
JavaScript
32
star
28

reachable-url

Given an URL, it resolves as fast as possible, performing a GET without downloading the body.
JavaScript
31
star
29

human-number

Convert number to a human readable string: `13500` β†’ `13.5K`
JavaScript
31
star
30

whoops

It makes simple create qualified errors.
JavaScript
31
star
31

count

counting things, as microservice
JavaScript
30
star
32

untracked

Universal way for ignoring unnecessary common files to fit your bundle
JavaScript
29
star
33

server-sandbox

Learn how to configure a server to provide typical services for the web.
Shell
28
star
34

json-stringify-deterministic

Deterministic version of JSON.stringify() so you can get a consistent hash from stringified results.
JavaScript
26
star
35

sails-hook-newrelic

Integrates newrelic with your Sails application
JavaScript
25
star
36

macdown-flatland-theme

Flatland theme for Mou Markdown editor
20
star
37

react-boilerplatinum

A React scaffold focused in developer experience
HTML
20
star
38

tweet-selection

Tweet selected text. Like Medium but out of the box.
JavaScript
18
star
39

finepack

Organizes and maintains readable your JSON files.
CoffeeScript
18
star
40

top-sites

List of the top 500 domains and pages on the web.
JavaScript
17
star
41

voll

A boolean expressions evaluator.
JavaScript
17
star
42

json-parse-async

The missing JSON.parse async interface.
CoffeeScript
17
star
43

eachdir

Run one or more commands in one or more dirs.
Shell
16
star
44

cloudflare-workers-kv

Node.js library to interact with CloudFlare Workers KV.
JavaScript
16
star
45

top-crawler-agents

A list of common crawler user agents useful for retrieving metadata from links.
JavaScript
15
star
46

hyperdiff

Find common, removed and added element between two collections.
JavaScript
15
star
47

awesome-full-text-search

A curated list of πŸ” full text search engines and stuff related with it.
15
star
48

sails-hook-winston

Integrates winston logging system with your Sails application
JavaScript
14
star
49

map-values-deep

Recursive lodash.mapValues
JavaScript
14
star
50

tom-example

A tom microservice example
Shell
14
star
51

is-emoji-keyword

Check if a word is a emoji shortcut.
CoffeeScript
14
star
52

emojis-keywords

Complete list of emoji shortcuts. The list is a 1:1 map of emojis-list.
JavaScript
14
star
53

simple-wappalyzer

A simple way to interacting with Wappalyzer.
JavaScript
14
star
54

dotfiles

.files, including ~/.osx β€” sensible hacker defaults for OS X
Shell
14
star
55

sort-keys-recursive

Sort the keys of an array/object recursively.
JavaScript
13
star
56

emojis-unicode

Complete list of standard Unicode codes that represent emojis.
JavaScript
13
star
57

process-stats

Human readable stats for your Node.js process.
JavaScript
12
star
58

is-url-http

Check if an URL is a valid HTTP URL.
JavaScript
11
star
59

promise-async

Adds Promises bindings for async library. Works with callbacks as well.
JavaScript
11
star
60

colorable-dominant

Create ARIA-compliant color themes based on a predominant color palette.
JavaScript
11
star
61

country-vat

Get a country VAT rate. ISO 3166-1 compliant.
JavaScript
10
star
62

superlock

A mutex/semaphore implementation made easy to use.
JavaScript
10
star
63

fetch-timeline-cli

Fetch Twitter user's timeline from your terminal ⚑.
JavaScript
10
star
64

html-urls

Get all urls from a HTML markup
JavaScript
10
star
65

req-country

Given a request, get the country associated with it. ISO 3166-1 alpha-2 compliant.
JavaScript
9
star
66

generator-git

πŸ“ Generate an Impeccable Tailored project
JavaScript
9
star
67

color-microservice

Get color information from any URL image microservice
JavaScript
9
star
68

aspect-ratio

Get the screen aspect ratio of a device.
JavaScript
8
star
69

react-atv-img-demo

Apple TV 3D parallax effect as component
JavaScript
8
star
70

bs-pretty-message

Overlay a fullscreen message to all browsers, but maintained.
HTML
8
star
71

use-query-state

React hook to set/retrieve state from URL query string.
JavaScript
8
star
72

git-garbage

Delete local git branches after deleting them on the remote repository.
Shell
8
star
73

cb2promise

It converts from standard NodeJS callback into a ES2015 Promise.
JavaScript
8
star
74

uno-urban

Simple and Elegant personal theme for Ghost.
HTML
8
star
75

is-european

Check if a country is part of the EU (European Union) or EEA (European Economic Area). ISO 3166-1 compliant.
JavaScript
8
star
76

doh-resolver

A (multi) DNS-over-HTTPS resolver for Node.js
JavaScript
8
star
77

twdown

Get MP4/MP3 video url from any Twitter video
JavaScript
7
star
78

array-list

Simple array list implementation.
JavaScript
7
star
79

pdf-microservice

Get the PDF version of a website as service.
JavaScript
7
star
80

kikobeats.com

ma website yo
HTML
6
star
81

afterglow-monokai-syntax

Afterglow Monokai syntax style for Atom
Less
6
star
82

hyper-flat

Flat Hyper theme
JavaScript
6
star
83

miconfig

Configuration loader for Node.js, browsers & Deno.
JavaScript
6
star
84

exists-file

Check if a file exists. A fs.exists implementation that is not deprecated.
JavaScript
6
star
85

awesome-cli-dx

A curated list of awesome CLI's pattern for building smooth experiences.
5
star
86

git-dirty

Ensures the working directory is clean and that there are no unpulled changes.
Shell
5
star
87

html-scripts

It parses HTML markup and returns you all the scripts.
JavaScript
5
star
88

microsoft-capitalize

Sentence-style capitalization in titles and headings based on Microsoft Styleguide
JavaScript
5
star
89

svg-gradient

Generate a SVG gradient from CSS
JavaScript
5
star
90

beauty-error

Getting a beauty error. Oriented for well printed errors. Be beauty, no ugly.
JavaScript
5
star
91

get-social-video-url

Get video URL from a social link (Facebook/Twitter/Vimeo/etc).
JavaScript
5
star
92

fetch-timeline

Fetch Twitter user timeline using a readable stream.
JavaScript
5
star
93

simple-dsl

Simple DSL based on <key,value> designed to work together fulltext search engines.
JavaScript
5
star
94

is-sql-injection

Check if a string contains an SQL injection.
JavaScript
5
star
95

superb-es

Get superb (spanish) like words.
JavaScript
5
star
96

is-tracking-domain

Determinate if a domain is a tracker
JavaScript
5
star
97

react-codecopy

A React component for "Copy to clipboard" button for your code snippets
JavaScript
5
star
98

react-atv-img

JavaScript
4
star
99

fmt-obj-cli

Pretty any JavaScript Object in your console
JavaScript
4
star
100

react-atv-logo

Clearbit API + Apple TV 3D Parallax
JavaScript
4
star