All Projects → Kikobeats → Cacheable Response

Kikobeats / Cacheable Response

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

Programming Languages

javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to Cacheable Response

Laravel Responsecache
Speed up a Laravel app by caching the entire response
Stars: ✭ 1,874 (+1093.63%)
Mutual labels:  cache
React Prerendered Component
🤔Partial hydration and caching in a pre-suspense era
Stars: ✭ 141 (-10.19%)
Mutual labels:  cache
Jstarcraft Core
目标是提供一个通用的Java核心编程框架,作为搭建其它框架或者项目的基础. 让相关领域的研发人员能够专注高层设计而不用关注底层实现. 涵盖了缓存,存储,编解码,资源,脚本,监控,通讯,事件,事务9个方面.
Stars: ✭ 150 (-4.46%)
Mutual labels:  cache
Xsnow
💮基于RxJava2+Retrofit2精心打造的Android基础框架,包含网络、上传、下载、缓存、事件总线、权限管理、数据库、图片加载,基本都是项目中必用功能,每个模块充分解耦,可自由拓展。
Stars: ✭ 1,678 (+968.79%)
Mutual labels:  cache
Create React Server
Server & middleware for React + Router + Redux with Server Side Rendering
Stars: ✭ 139 (-11.46%)
Mutual labels:  server-rendering
Ngx Cache
Cache utility for Angular
Stars: ✭ 144 (-8.28%)
Mutual labels:  cache
Wp Spider Cache
Your friendly neighborhood caching solution for WordPress
Stars: ✭ 133 (-15.29%)
Mutual labels:  cache
Layercache
Caching made simple for Android and Java.
Stars: ✭ 155 (-1.27%)
Mutual labels:  cache
Olric
Distributed cache and in-memory key/value data store. It can be used both as an embedded Go library and as a language-independent service.
Stars: ✭ 2,067 (+1216.56%)
Mutual labels:  cache
Strapi Middleware Cache
🔌 A cache middleware for https://strapi.io
Stars: ✭ 146 (-7.01%)
Mutual labels:  cache
Sequelize Transparent Cache
Simple to use and universal cache layer for Sequelize
Stars: ✭ 137 (-12.74%)
Mutual labels:  cache
Entityframeworkcore.cacheable
EntityFrameworkCore second level cache
Stars: ✭ 138 (-12.1%)
Mutual labels:  cache
Nuster
A high performance HTTP proxy cache server and RESTful NoSQL cache server based on HAProxy
Stars: ✭ 1,825 (+1062.42%)
Mutual labels:  cache
Identity cache
IdentityCache is a blob level caching solution to plug into Active Record. Don't #find, #fetch!
Stars: ✭ 1,733 (+1003.82%)
Mutual labels:  cache
Android Cache Fix Gradle Plugin
Gradle plugin to fix Android caching problems
Stars: ✭ 150 (-4.46%)
Mutual labels:  cache
Cachewebview
Custom implement Android WebView cache, offline website, let cahe config more simple and flexible
Stars: ✭ 1,767 (+1025.48%)
Mutual labels:  cache
Go Cache
This project encapsulates multiple db servers, redis、ledis、memcache、file、memory、nosql、postgresql
Stars: ✭ 143 (-8.92%)
Mutual labels:  cache
Cachew
Transparent and persistent cache/serialization powered by type hints
Stars: ✭ 155 (-1.27%)
Mutual labels:  cache
Libcache
A Lightweight in-memory key:value cache library for Go.
Stars: ✭ 152 (-3.18%)
Mutual labels:  cache
Cachego
Golang Cache component - Multiple drivers
Stars: ✭ 148 (-5.73%)
Mutual labels:  cache

cacheable-response

Last version Build Status 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.

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: 7200000 // 2 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, s-maxage=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
cache-control: public, max-age=7170, s-maxage=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 # MISS (forcing invalidation)

API

cacheableResponse([options])

options

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.

ttl

Type: number
Default: 7200000

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.

compress

Type: boolean
Default: false

Enable compress/decompress data using brotli compression format.

If you enable it, you need to an additional iltorb package:

npm install iltorb
revalidate

Type: function|number
Default: ttl => ttl / 24

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.

You can provide a function, it will receive ttl as first parameter or a fixed value.

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

getKey

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

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

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 = 7200000 // 2 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.

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.

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, s-maxage=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, s-maxage=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 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!

Express

Next.js

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

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].