@npm/spife-ratelimit

Middleware that adds [Token Bucket]-style ratelimiting to [Spife].

Usage no npm install needed!

<script type="module">
  import npmSpifeRatelimit from 'https://cdn.skypack.dev/@npm/spife-ratelimit';
</script>

README

spife-ratelimiter

Middleware that adds Token Bucket-style ratelimiting to Spife.

// settings.js:
module.exports.MIDDLEWARE = {
  ['@npm/spife-ratelimiting', {
    redisUrl: 'redis://localhost:6379', // let it connect to redis
    redisClient,                        // (or give it a client)

    costHeader: 'npm-cost',             // the "cost" header to use
                                        // for determining how many
                                        // tokens a request took

    clock: Date.now,                    // if you would like time to
                                        // move to the beat of a
                                        // different drum

    getBucket (spifeRequest) {          // given a request, return
                                        // an object describing its
                                        // token bucket
      return {
        capacity: 100,                  // how many tokens does
                                        // the bucket hold?

        interval: 60,                   // in minutes, how long
                                        // does the bucket take to
                                        // fill up?

        key: String                     // what should the bucket be
                                        // named?
      }
    }
  }]
}

// views.js:
const reply = require('@npm/spife/reply')
const cost = require('@npm/spife-ratelimiter/decorator')

module.exports = {
  // a view can declare how much it costs up-front:
  index: cost(index, 5),
  other
}

function index (req, context) {
  return 'I cost five tokens!'
}

function other (req, context) {
  return reply.header(
    'I cost a hundred tokens sometimes',
    'npm-cost',
    Math.random() > 0.5 ? 100 : 0
  )
}

This is implemented in redis by keeping two keys per bucket: one that tracks the current number of tokens, and one that tracks the last update time. Both keys are expired at interval, and updated atomically using a Lua script.