juckerf / feathers-hooks-rediscache

Set of caching hooks and routes for feathersjs.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Redis Cache

Build Status Coverage Status

Cache any route with redis

Installation

npm install feathers-hooks-rediscache --save

Purpose

The purpose of these hooks is to provide redis caching for APIs endpoints. Using redis is a very good option for clusturing your API. As soon as a request is cached it is available to all the other nodes in the cluster, which is not true for usual in memory cache as each node has its own memory allowcated. This means that each node has to cache all requests individually.

Each request to an endpoint can be cached. Route variables and params are cached on a per request base. If a param to call is set to true and then to false two responses will be cached.

The cache can be purged for an individual route, but also for a group of routes. This is very useful if you have an API endpoint that creates a list of articles, and an endpoint that returns an individual article. If the article is modified, the list of articles should, most likely, be purged as well. This can be done by calling one endpoint.

In the same fashion if you have many variants of the same endpoint that return similar content based on parameters you can bust the whole group as well:

/articles // list
/articles/article //individual item
/articles/article?markdown=true // variant

These are all listed in a redis list under group-articles and can be busted by calling /cache/clear/group/article or /cache/clear/group/articles it does not matter. All urls will be purged.

It was meant to be used over http, not tested with sockets.

Documentation

Add the different hooks. The order matters (see below). A cache object will be added to your response. This is useful as other systems can use this object to purge the cache if needed.

Configuration

A cache object can be added to the default feathers configuration

  "redisCache" : {
    "defaultDuration": 3600,
    "parseNestedRoutes": true,
    "removePathFromCacheKey": true
  };

The default duration can be configured by passing the duration in seconds to the property defaultDuration. If your API uses nested routes like /author/:authorId/book you should turn on the option parseNestedRoutes. Otherwise you could have conflicting cache keys. removePathFromCacheKey is an option that is useful when working with content and slugs. If when this option is turned on you can have the following issue. If your routes use IDs then you could have a conflict and the cache might return the wrong value:

  user/123
  article/123

both items with id 123 would be saved under the same cache key... thus replacing each other and returning one for the other, thus by default the key includes the path to diferenciate them. when working with content you could have an external system busting the cache that is not aware of your API routes. That system would know the slug, but cannot bust the cache as it would have to call /cache/clear/single/:path/target, with this option that system can simply call :target which would be the slug/alias of the article.

Available routes:

/cache/index // returns an array with all the keys
/cache/clear // clears the whole cache
/cache/clear/single/:target // clears a single route if you want to purge a route with params just adds them target?param=1
/cache/clear/group/:target // clears a group

Complete Example

Here's an example of a Feathers server that uses feathers-hooks-rediscache.

const feathers = require('feathers');
const rest = require('feathers-rest');
const hooks = require('feathers-hooks');
const bodyParser = require('body-parser');
const errorHandler = require('feathers-errors/handler');
const routes = require('feathers-hooks-rediscache').cacheRoutes;
const redisClient = require('feathers-hooks-rediscache').redisClient;
const cache = require('feathers-hooks-rediscache').redisCache;

// Initialize the application
const app = feathers()
  .configure(rest())
  .configure(hooks())
  .configure(redisClient)
  .configure(cache)
  // Needed for parsing bodies (login)
  .use(bodyParser.json())
  .use(bodyParser.urlencoded({ extended: true }))
  // add the cache routes (endpoints) to the app
  .use('/cache', routes())
  .use(errorHandler());

app.listen(3030);

console.log('Feathers app started on 127.0.0.1:3030');

Add hooks on the routes that need caching

//services/<service>.hooks.js

const redisBefore = require('feathers-hooks-rediscache').redisBeforeHook;
const redisAfter = require('feathers-hooks-rediscache').redisAfterHook;
const cache = require('feathers-hooks-rediscache').hookCache;


module.exports = {
  before: {
    all: [],
    find: [redisBefore()],
    get: [redisBefore()],
    create: [],
    update: [],
    patch: [],
    remove: []
  },

  after: {
    all: [],
    find: [cache({duration: 3600 * 24 * 7}), redisAfter()],
    get: [cache({duration: 3600 * 24 * 7}), redisAfter()],
    create: [],
    update: [],
    patch: [],
    remove: []
  },

  error: {
    all: [],
    find: [],
    get: [],
    create: [],
    update: [],
    patch: [],
    remove: []
  }
};
  • the duration is in seconds and will automatically expire
  • you may just use cache() without specifying a duration, any request will be cached for a day or with the global configured value (see configuration above).

To configure the redis connection the feathers configuration system can be used.

//config/default.json
{
  "host": "localhost",
  "port": 3030,
  "redis": {
    "host": "my-redis-service.example.com",
    "port": 1234
  }
}
  • if no config is provided, default config from the redis module is used

License

Copyright (c) 2017

Licensed under the MIT license.

About

Set of caching hooks and routes for feathersjs.

License:MIT License


Languages

Language:JavaScript 100.0%