-
-
Notifications
You must be signed in to change notification settings - Fork 162
Hapi plugin
Roman edited this page Nov 10, 2023
·
6 revisions
'use strict';
const Boom = require('boom');
const redis = require('ioredis');
const {RateLimiterRedis} = require('rate-limiter-flexible');
const internals = {
pluginName: 'rateLimitRedisPlugin',
};
internals.redisClient = new Redis({
host: 'redis',
port: 6379,
enableOfflineQueue: false,
});
internals.rateLimiter = new RateLimiterRedis({
storeClient: internals.redisClient,
keyPrefix: 'hapi-plugin',
points: 10, // 10 requests
duration: 1, // per 1 second by IP
});
module.exports = {
name: internals.pluginName,
version: '1.0.0',
register: function (server) {
server.ext('onPreAuth', async (request, h) => {
try {
await internals.rateLimiter.consume(request.info.remoteAddress);
return h.continue;
} catch (rej) {
let error;
if (rej instanceof Error) {
// If some Redis error and `insuranceLimiter` is not set
error = Boom.internal('Try later');
} else {
// Not enough points to consume
error = Boom.tooManyRequests('Rate limit exceeded');
error.output.headers['Retry-After'] = Math.round(rej.msBeforeNext / 1000) || 1;
}
return error;
}
});
}
};
onPreAuth
event is used to rate limit requests for all application routes. Depending on requirements you may use onPostAuth
, onPostHandler
, etc (read about request lifecycle in official hapi docs)
'use strict';
const Hapi = require('hapi');
const server = Hapi.server({
port: 3000,
host: 'localhost'
});
server.route({
method: 'GET',
path: '/',
handler: (request, h) => {
return 'Hello, world!';
}
});
const init = async () => {
await server.register(require('./plugin/rateLimitRedis'));
await server.start();
};
process.on('unhandledRejection', (err) => {
process.exit(1);
});
init();
Mongo, Memcached, MySQL or any other limiter from this package can be used with the same approach.
Get started
Middlewares and plugins
Migration from other packages
Limiters:
- Redis
- Memory
- DynamoDB
- Prisma
- MongoDB (with sharding support)
- PostgreSQL
- MySQL
- BurstyRateLimiter
- Cluster
- PM2 Cluster
- Memcached
- RateLimiterUnion
- RateLimiterQueue
Wrappers:
- RLWrapperBlackAndWhite Black and White lists
Knowledge base:
- Block Strategy in memory
- Insurance Strategy
- Comparative benchmarks
- Smooth out traffic peaks
-
Usage example
- Minimal protection against password brute-force
- Login endpoint protection
- Websocket connection prevent flooding
- Dynamic block duration
- Different limits for authorized users
- Different limits for different parts of application
- Block Strategy in memory
- Insurance Strategy
- Third-party API, crawler, bot rate limiting