GithubHelp home page GithubHelp logo

eu's Introduction

Eu is a wrapper around request which can cache HTTP GET requests based on response headers - just like a browser does.

It is used to lower latency when consuming data from HTTP/REST APIs that have proper caching headers.

"Eu" means "gotten" in French.

This library is heavily inspired from Kevin Swiber's request-caching.

Features

  • Multiple cache stores:
    • Redis (built-in)
    • In-memory based on LRU (built-in)
    • Medea (3rd party eu-medea-store plugin by Kevin Swiber)
  • Supports both public and private caching.
  • Takes advantage of the ETag response header by using the If-None-Match request header.
  • Takes advantage of the Last-Modified response header by using the If-Modified-Since request header.
  • Cache TTL is based on the Expires response header or max-age value in Cache-Control, but can be overridden.
  • Highly customisable with sensible defaults.

Usage

Usage is similar to request.get. The main difference is that you have to create an Eu instance:

var Eu = require('eu');
var eu = new Eu(cache); // See below for details about how to create a cache

eu.get('http://some.url', function(err, res, body) {
});

// Or pass in request options:
eu.get('http://some.url', {json: true}, function(err, res, body) {
});

A cache uses a store to store cached responses:

In-memory store

var LRU = require('lru-cache');
var store = new Eu.MemoryStore(new LRU());
var cache = new Eu.Cache(store);

Redis store

var redis = require('redis').createClient();
var store = new Eu.RedisStore(redis);
var cache = new Eu.Cache(store);

You can also create a NullCache, which does nothing and doesn't require a store:

Null cache

var cache = new Eu.NullCache();

Cache key name spacing

You should always provide a prefix which prefixes the key with the name of your app (or API). When you invoke Cache.flush, it will only flush the keys starting with that prefix. If you don't specify a prefix, you'll flush the entire cache.

var prefix = 'yourapp:';
var cache = new Eu.Cache(store, prefix);

cache.flush(cb); // only the 'yourapp:*' keys get flushed

Private caching

Some HTTP responses should be cached privately - i.e. they shouldn't be available for other users. This is the case when the server responds with Cache-Control: private.

To handle this you should construct the Cache with a privateSuffix String argument. This suffix will be appended to the key when caching a private response.

var prefix = 'yourapp:';
var unique = req.user.id; // or req.cookies['connect.sid']
var privateSuffix = ':private:' + unique;
var cache = new Eu.Cache(store, prefix, privateSuffix);

You will get an error if no privateSuffix was provided when caching a private response.

For servers that don't reply with a Cache-Control: private header, you can force the request to be cached privately:

cache.get(url, { private: true }, function (err, val) {
  ...
});

Eu will always look in the public cache first, and then in the private cache if there was no hit in the public cache.

Cache entry expiry time

Every time a response is cached, it is cached with an expiry time. This is a timestamp indicating how long the cache entry is valid for. (This is not the same as TTL - Time to Live. See next section).

When Eu finds an entry in the cache it will consult this timestamp to decide whether the entry is still valid - i.e. is the expiry time in the future.

If it's valid, the response is returned immediately. If not, a HTTP request will be issued, setting the If-None-Match request header to the value of the cached ETag value, and the If-Modified-Since request header to the value of the cached Last-Modified value.

If the server responds with 304 Not Modified the cached response will be returned even though it is expired (the server has confirmed that even though it is expired, it hasn't changed).

By default the expiry time is determined by either the Cache-Control max-age or Expires response header. If neither of these headers are set, or if you want to cache more aggressively than what they indicate, you can override this in the options passed to eu.get:

function expiryTimeMillis() {
  return 8640000000000000; // cache forever
}
cache.get(url, { expiryTimeMillis: expiryTimeMillis }, function (err, val) {
  ...
});

TTL

By default, Eu will store entries in the cache with the TTL (Time to Live) equal to the cache expiry time (see above).

If the expiry time is undefined, the response will be cached forever, or until the cache discards it, using whatever expiry algorithm it uses, such as LIFO or FIFO.

You can override the default TTL by supplying your own ttl function:

function myTtl(ttl) {
  return ttl * 1000; // cache it longer than the server told us to.
}

var cache = new Eu.Cache(store, null, null, myTtl);

Debugging

Just set DEBUG=eu in your shell to see debug info.

For extra verbose output (print request and response headers) set DEBUG=eu,eu:*

eu's People

Contributors

aslakhellesoy avatar jarib avatar kevinswiber avatar mattwynne avatar rwaldin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

eu's Issues

New cache store released: eu-medea-store

I'm not sure if you're tracking new cache stores anywhere, so this might just be a quick FYI.

I've been maintaining a pure JavaScript persistent key-value storage library named Medea.

I built the eu-medea-store module to marry Eu with Medea.

So... if you need a legit (not in-memory) cache store that is persistent, requires no native modules, and runs in-process.... here you go!

Extend previous cache expiry on 304 response?

Atm previously cached reponses gets returned if the server responds with 304, great ๐Ÿ‘ Although as the cached response expiry isnt extended, all subsequent requests will still perform requests against the server.

Any thoughts on extending the cachedResponse.expiryTimeMillis on 304 responses, increasing the possibility of hitting the cache immediately instead of requesting the server?

Cache 302 responses?

According to the HTTP spec, a 302 response is

cacheable if indicated by a Cache-Control or Expires header field.

Even if we changed the logic in eu, request() won't emit 302 responses unless it's passed {followRedirect: false}

Can we make eu cache 302 responses without users having to implement redirection themselves? What would be the best approach?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.