Rate limiting stampede protection for express
An express middleware for rate limiting an application to provide stampede protection.
const cattleguard = require('cattleguard');
const redis = require('redis');
const rClient = redis.createClient();
// Cattleguard now expects the `set` method to include a ttl value. If your
// store does not accept this value by default you will need to wrap your store
// with a method that performs both the set and expire.
// For example:
const client = {
get(...args) {
rClient.get(...args);
},
set(key, val, ttl, cb) {
rClient.set(key, val, (err) => {
if (err) {
return cb(err);
}
rClient.expire(ttl, cb);
})
}
}
const config = {
total: 300,
expire: 1000,
onRateLimited: (req, res, next) => {
res.status(503).send('Service Unavailable');
}
};
// Rate limiting for _all_ routes.
app.use(cattleguard(config, client));
// Rate limiting for a single route.
config.perRoute = true;
app.post('/blogs', cattleguard(config, client), (req, res, next) => {
// ...
});
// Rate limiting for a subset of routes based on method.
config.perMethod = true;
app.route('/blogs')
.all(cattleguard(config, client))
.post((req, res, next) => {
// Will have its own rate limit.
})
.get((req, res, next) => {
// Will have its own rate limit.
});
// Rate limiting based on request criteriea.
config.lookup = (req) => req.headers['x-forwarded-for'];
app.post('/blogs', cattleguard(config, client), (req, res, next) => {
// ...
});
config
- Rate limit configuration, contains:
total
: integer, the number of requests per a time period to allow beforeexpire
: integer, the time period in milliseconds to limit requests.onRateLimited
: function, the method to execute when a rate limit has beenreq
: The reequest object.res
: The response object.next
: The method to execute after the on rate limited method, ifperRoute
: boolean, true if rate limiting should happen per route.false
perMethod
: boolean, true if rate limiting should happen per HTTP method.false
lookup
: function, used to return an identifier for the user requesting.undefined
store
- A store to maintain the rate limit counts in. Must provide get andget
: gets a value from the store.
key
- The key for the rate limit information.callback
- A callback to execute after getting, parameters are err andset
: sets a value in the store.
key
- The key for the rate limit information.value
- The value to store.ttl
- The timeout in seconds for the rate limit information.callback
- A callback to execute after setting, parameters are err.This module was heavily influenced by express-limiter but allows application rate limiting in the interest of guarding against backend failures, rather than the consumer only rate limiting approach that express-limiter takes.