Rate limiting middleware for Express applications built on redis
npm install express-limiter --save
var express = require('express') var app = express() var client = require('redis').createClient() var limiter = require('express-limiter')(app, client) /** * you may also pass it an Express 4.0 `Router` * * router = express.Router() * limiter = require('express-limiter')(router, client) */ limiter({ path: '/api/action', method: 'get', lookup: ['connection.remoteAddress'], // 150 requests per hour total: 150, expire: 1000 * 60 * 60 }) app.get('/api/action', function (req, res) { res.send(200, 'ok') })
limiter(options)
path:Stringoptional route path to the requestmethod:Stringoptional http method. acceptsget,post,put,delete, and of course Express'alllookup:Function|String|Array.<String>value lookup on the request object. Can be a single value, array or function. See examples for common usagestotal:Numberallowed number of requests before getting rate limitedexpire:Numberamount of time inmsbefore the rate-limited is resetwhitelist:function(req)optional param allowing the ability to whitelist. returnboolean,trueto whitelist,falseto passthru to limiter.skipHeaders:Booleanwhether to skip sending HTTP headers for rate limits ()ignoreErrors:Booleanwhether errors generated from redis should allow the middleware to call next(). Defaults to false.onRateLimited:Functioncalled when a request exceeds the configured rate limit.
// limit by IP address limiter({ ... lookup: 'connection.remoteAddress' ... }) // or if you are behind a trusted proxy (like nginx) limiter({ lookup: 'headers.x-forwarded-for' }) // by user (assuming a user is logged in with a valid id) limiter({ lookup: 'user.id' }) // limit your entire app limiter({ path: '*', method: 'all', lookup: 'connection.remoteAddress' }) // limit users on same IP limiter({ path: '*', method: 'all', lookup: ['user.id', 'connection.remoteAddress'] }) // whitelist user admins limiter({ path: '/delete/thing', method: 'post', lookup: 'user.id', whitelist: function (req) { return !!req.user.is_admin } }) // skip sending HTTP limit headers limiter({ path: '/delete/thing', method: 'post', lookup: 'user.id', whitelist: function (req) { return !!req.user.is_admin }, skipHeaders: true }) // call a custom limit handler limiter({ path: '*', method: 'all', lookup: 'connection.remoteAddress', onRateLimited: function (req, res, next) { next({ message: 'Rate limit exceeded', status: 429 }) } }) // with a function for dynamic-ness limiter({ lookup: function(req, res, opts, next) { if (validApiKey(req.query.api_key)) { opts.lookup = 'query.api_key' opts.total = 100 } else { opts.lookup = 'connection.remoteAddress' opts.total = 10 } return next() } })
app.post('/user/update', limiter({ lookup: 'user.id' }), function (req, res) { User.find(req.user.id).update(function (err) { if (err) next(err) else res.send('ok') }) })
Happy Rate Limiting!