UNPKG

@fastify/rate-limit

Version:

A low overhead rate limiter for your routes

119 lines (107 loc) 2.79 kB
'use strict' // Example of a Custom Store using Knex.js ORM for SQLite database // Below is an example table to store rate limits that must be created // in the database first // // CREATE TABLE "RateLimits" ( // "Route" TEXT, // "Source" TEXT, // "Count" INTEGER, // "TTL" NUMERIC, // PRIMARY KEY("Source") // ); // // CREATE UNIQUE INDEX "idx_uniq_route_source" ON "RateLimits" (Route, Source); // const Knex = require('knex') const fastify = require('fastify')() const knex = Knex({ client: 'sqlite3', connection: { filename: './db.sqlite' } }) function KnexStore (options) { this.options = options this.route = '' } KnexStore.prototype.routeKey = function (route) { if (route) { this.route = route } else { return route } } KnexStore.prototype.incr = function (key, cb) { const now = (new Date()).getTime() const ttl = now + this.options.timeWindow knex.transaction(function (trx) { trx .where({ Route: this.route, Source: key }) .then(d => { if (d.TTL > now) { trx .raw(`UPDATE RateLimits SET Count = 1 WHERE Route='${this.route}' AND Source='${key}'`) .then(() => { cb(null, { current: 1, ttl: d.TTL }) }) .catch(err => { cb(err, { current: 0 }) }) } else { trx .raw(`INSERT INTO RateLimits(Route, Source, Count, TTL) VALUES('${this.route}', '${key}',1,${d.TTL || ttl}) ON CONFLICT(Route, Source) DO UPDATE SET Count=Count+1,TTL=${ttl}`) .then(() => { cb(null, { current: d.Count ? d.Count + 1 : 1, ttl: d.TTL || ttl }) }) .catch(err => { cb(err, { current: 0 }) }) } }) .catch(err => { cb(err, { current: 0 }) }) }) } KnexStore.prototype.child = function (routeOptions) { const options = Object.assign(this.options, routeOptions) const store = new KnexStore(options) store.routeKey(routeOptions.routeInfo.method + routeOptions.routeInfo.url) return store } fastify.register(require('../../fastify-rate-limit'), { global: false, max: 10, store: KnexStore, skipOnError: false } ) fastify.get('/', { config: { rateLimit: { max: 10, timeWindow: '1 minute' } } }, (_req, reply) => { reply.send({ hello: 'from ... root' }) }) fastify.get('/private', { config: { rateLimit: { max: 3, timeWindow: '1 minute' } } }, (_req, reply) => { reply.send({ hello: 'from ... private' }) }) fastify.get('/public', (_req, reply) => { reply.send({ hello: 'from ... public' }) }) fastify.listen({ port: 3000 }, err => { if (err) throw err console.log('Server listening at http://localhost:3000') })