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

@lob/steve

v1.0.0

Published

Rate-limit any operation, backed by Redis

Downloads

32

Readme

Steve (a Redis-backed rate limiter)

Based on redis-rate-limiter.

NPM License

Build Status Dependencies Dev dependencies

Rate-limit any operation, backed by Redis.

  • Inspired by ratelimiter
  • But uses a fixed-window algorithm
  • Great performance (>10000 checks/sec on local redis)
  • No race conditions

Very easy to plug into Express or Restify to rate limit your Node.js API.

Usage

Step 1: create a Redis connection

var redis = require('redis');
var client = redis.createClient(6379, 'localhost', {enable_offline_queue: false});

Step 2: create your rate limiter

var rateLimiter = require('redis-rate-limiter');
var limits = { window: 60, limit: { test: 100, live: 1000 }};
var limit = rateLimiter.create({
  redis: client,
  key: function(x) { return x.id },
  rate: '100/minute'
}
limits);

And go

limit(request, function(err, rate) {
  if (err) {
    console.warn('Rate limiting not available');
  } else {
    console.log('Rate window: '  + rate.window);  // 60
    console.log('Rate limit: '   + rate.limit);   // 100
    console.log('Rate current: ' + rate.current); // 74
    if (rate.over) {
      console.error('Over the limit!');
    }
  }
});

Options

redis

A pre-created Redis client. Make sure offline queueing is disabled.

var client = redis.createClient(6379, 'localhost', {
  enable_offline_queue: false
});

key

The key is how requests are grouped for rate-limiting. Typically, this would be a user ID, a type of operation... There are several helpers built-in:

// identify users by IP
key: 'ip'

// identify users by their IP network (255.255.255.0 mask)
key: 'ip/32'

// identify users by the X-Forwarded-For header
// careful: this is just an HTTP header and can easily be spoofed
key: 'x-forwarded-for'

You can also specify any custom function:

// rate-limit each user separately
key: function(x) { return x.user.id; }

// rate limit per user and operation type
key: function(x) { return x.user.id + ':' + x.operation; }

// rate limit everyone in the same bucket
key: function(x) { return 'single-bucket'; }

window

This is the duration over which rate-limiting is applied, in seconds.

// rate limit per minute
window: 60

// rate limit per hour
window: 3600

Note that this is not a rolling window. If you specify 10 requests / minute, a user would be able to execute 10 requests at 00:59 and another 10 at 01:01. Then they won't be able to make another request until 02:00.

limit

This is the total number of requests a unique key can make during the window.

limit: 100

rate

Rate is a shorthand notation to combine limit and window.

rate: '10/second'
rate: '100/minute'
rate: '1000/hour'

Or the even shorter

rate: '10/s'
rate: '100/m'
rate: '100/h'

Note: the rate is parsed ahead of time, so this notation doesn't affect performance.

You can also specify any custom function:

// rate-limit different users
limit: function (x, limits) {
  return {
    limit: x.is_test ? limits.test : limits.live,
    window: limits.window ? limits.window : 60, // default to 60s
  }
}

HTTP middleware

This package contains a pre-built middleware, which takes the same options

var rateLimiter = require('redis-rate-limiter');

var middleware = rateLimiter.middleware({
  redis: client,
  key: 'ip',
  rate: '100/minute'
});

server.use(middleware);

It rejects any rate-limited requests with a status code of HTTP 429, and an empty body.

Note: if you want to rate limit several routes individually, don't forget to use the route name as part of the key, for example using Restify:

function ipAndRoute(req) {
  return req.connection.remoteAddress + ':' + req.route.name;
}

server.get(
  {name: 'routeA', path: '/a'},
  rateLimiter.middleware({redis: client, key: ipAndRoute, rate: '10/minute'}),
  controllerA
);

server.get(
  {name: 'routeB', path: '/b'},
  rateLimiter.middleware({redis: client, key: ipAndRoute, rate: '20/minute'}),
  controllerB
);