npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

request-throttler

v2.0.0

Published

Middleware to throttle requests by a single use/set of users

Downloads

12

Readme

request-throttler

Middleware to throttle requests by a single use/set of users. Helpful in reducing server load, preventing datamining, and stifling brute force attacks.

If a given user goes above the allowed requestsPerSecond, a 503 is returned for every request until the average drops. User state and request count is kept int the redis database and reset after timeToLive seconds. The user request count is stored in a redis database, specified during configuration.

It's important to note that the count can only be updated as fast as the redis database allows access. if two requests come in at the same time, the count will only be increased by one.

Note: The --harmony flag is required for both koa and express

Key

Usage

koa

app.use(throttler.koa({
  port              : 6379,
  host              : 127.0.0.1,
  requestsPerSecond : 50,
  timeToLive        : 60,
  throttler         : function *() {
    console.log('I\'ve been throttled!');
    this.status = 503;
    this.body = 'Service unavailable'
  },
  error : function *(error) {
    console.log(error.stack);
    this.status = 500;
    this.body = 'Internal server error'  
  }
}));

express

app.use(throttler.express({
  port              : 6379,
  host              : 127.0.0.1,
  requestsPerSecond : 50,
  timeToLive        : 60,
  throttler         : function () {
    console.log('I\'ve been throttled!');
    res.status(503).send('Service unavailable');
  },
  error : function (error) {
    console.log(error.stack);
    res.status(500).send('Internal server error');
  }
}));

Duck type

// app is express or koa

throttler(app, {
  port              : 6379,
  host              : 127.0.0.1,
  requestsPerSecond : 50,
  timeToLive        : 60,
})

Configuration

config.host

  • Optional
  • The host where the redis database can be accessed
  • Default: 127.0.0.1
config.host = 127.0.0.1

config.port

  • Optional
  • The port where the redis database can be accessed
  • Default: 6379
config.port = 6379

config.requestsPerSecond

  • Required
  • The number of request per second allowed by a user
  • Make sure to base this on uniqueness of the fingerprint
config.requestsPerSecond = 30;

config.timeToLive

  • Required
  • The lifespan (in seconds) of the fingerprint store
  • Lower lifespan will cause faster fingerprint expiration and cut down on storage size
  • Higher lifespan will allow a users request to normalize over time (bursts will be less likely to throttle the user)
config.timeToLive = 60;

config.throttler

  • Optional
  • The handler called when a user is throttled
  • Default: sends a 503 and generic Service unavailable message
// express
config.throttler = function () {
  console.log('I\'ve been throttled!');
  res.status(503).send('Service unavailable');
}

//koa
config.throttler = function *(error) {
  console.log(error.stack);
  this.status = 500;
  this.body = 'Internal server error'  
}

config.error

  • Optional
  • The handler called if an error occurs
  • Default: sends a 500 and generic Internal server error message
// express
config.error = function (error) {
  console.log(error.stack);
  res.status(500).send('Internal server error');
}

//koa
config.error = function *(error) {
  console.log(error.stack);
  this.status = 500;
  this.body = 'Internal server error'  
}

Customization

Redis Workarounds

The redis store methods and be overridden, and redis can be removed entirely if desired. The following methods should be used

config.client

  • Must be an object with get(stringKey, callback) and set(stringKey, stringValue, callback)
config.client = {
  get: function (key, callback) {
    return yourGetOperation(key, function (error, result) {
      return callback(error, result);
    });
  },
  set: function (key, value, callback) {
    return yourSetOperation(key, value, function (error, result) {
      return callback(error, result);
    });
  }
}

config.getFingerprint

  • Generator function to get a fingerprint
config.getFingerprint = function *(key) {
  yield yourGetOperation(key);
}

config.setFingerprint

  • Generator function to set a fingerprint
config.setFingerprint = function *(key, newRequestCount) {
  yield yourSetOperation(key, newRequestCount);
}