glimit

A framework-agnostic rate limiter for Gleam. 💫

This module provides a rate limiter that can be used to limit the number of requests that can be made to a given function or handler within a given time frame.

The rate limiter is implemented as an actor that keeps track of the number of hits for a given identifier within the last second, minute, and hour. When a hit is received, the actor checks the rate limits and either allows the hit to pass or rejects it.

The rate limiter can be configured with rate limits per second, minute, and hour, and a handler function that is called when the rate limit is reached. The rate limiter can be applied to a function or handler using the apply function, which returns a new function that checks the rate limit before calling the original function.

Example

import glimit

let limiter =
  glimit.new()
  |> glimit.per_second(10)
  |> glimit.per_minute(100)
  |> glimit.per_hour(1000)
  |> glimit.identifier(fn(request) { request.ip })
  |> glimit.handler(fn(_request) { "Rate limit reached" })
  |> glimit.build()

let handler =
  fn(_request) { "Hello, world!" }
  |> glimit.apply(limiter)

Types

A rate limiter.

pub type RateLimiter(a, b, id) {
  RateLimiter(
    subject: Subject(actor.Message(id)),
    handler: fn(a) -> b,
    identifier: fn(a) -> id,
  )
}

Constructors

  • RateLimiter(
      subject: Subject(actor.Message(id)),
      handler: fn(a) -> b,
      identifier: fn(a) -> id,
    )

A builder for configuring the rate limiter.

pub type RateLimiterBuilder(a, b, id) {
  RateLimiterBuilder(
    per_second: Option(Int),
    per_minute: Option(Int),
    per_hour: Option(Int),
    identifier: Option(fn(a) -> id),
    handler: Option(fn(a) -> b),
  )
}

Constructors

  • RateLimiterBuilder(
      per_second: Option(Int),
      per_minute: Option(Int),
      per_hour: Option(Int),
      identifier: Option(fn(a) -> id),
      handler: Option(fn(a) -> b),
    )

Functions

pub fn apply(
  func: fn(a) -> b,
  limiter: RateLimiter(a, b, c),
) -> fn(a) -> b

Apply the rate limiter to a request handler or function.

pub fn apply2(
  func: fn(a, b) -> c,
  limiter: RateLimiter(#(a, b), c, d),
) -> fn(a, b) -> c

Apply the rate limiter to a request handler or function with two arguments.

Note: this function folds the two arguments into a tuple before passing them to the identifier or handler functions.

Example

import glimit

let limiter =
  glimit.new()
  |> glimit.per_hour(1000)
  |> glimit.identifier(fn(i: #(String, String)) {
    let #(a, _) = i
    a
  })
  |> glimit.handler(fn(_) { "Rate limit reached" })
  |> glimit.build()

let handler =
  fn(a, b) { a <> b }
  |> glimit.apply2(limiter)
pub fn apply3(
  func: fn(a, b, c) -> d,
  limiter: RateLimiter(#(a, b, c), d, e),
) -> fn(a, b, c) -> d

Apply the rate limiter to a request handler or function with three arguments.

Note: this function folds the three arguments into a tuple before passing them to the identifier or handler functions.

pub fn apply4(
  func: fn(a, b, c, d) -> e,
  limiter: RateLimiter(#(a, b, c, d), e, f),
) -> fn(a, b, c, d) -> e

Apply the rate limiter to a request handler or function with four arguments.

Note: this function folds the four arguments into a tuple before passing them to the identifier or handler functions.

⚠️ For functions with more than four arguments, you’ll need to write a custom wrapper function that folds the arguments into a tuple before passing them to the rate limiter. This is because Gleam does not support variadic functions, because the BEAM VM identifies functions by their arity.

pub fn build(
  config: RateLimiterBuilder(a, b, c),
) -> RateLimiter(a, b, c)

Build the rate limiter.

Panics if the rate limiter actor cannot be started or if the identifier function or handler function is missing.

pub fn handler(
  limiter: RateLimiterBuilder(a, b, c),
  handler: fn(a) -> b,
) -> RateLimiterBuilder(a, b, c)

Set the handler to be called when the rate limit is reached.

pub fn identifier(
  limiter: RateLimiterBuilder(a, b, c),
  identifier: fn(a) -> c,
) -> RateLimiterBuilder(a, b, c)

Set the identifier function to be used to identify the rate limit.

pub fn new() -> RateLimiterBuilder(a, b, c)

Create a new rate limiter builder.

pub fn per_hour(
  limiter: RateLimiterBuilder(a, b, c),
  limit: Int,
) -> RateLimiterBuilder(a, b, c)

Set the rate limit per hour.

pub fn per_minute(
  limiter: RateLimiterBuilder(a, b, c),
  limit: Int,
) -> RateLimiterBuilder(a, b, c)

Set the rate limit per minute.

pub fn per_second(
  limiter: RateLimiterBuilder(a, b, c),
  limit: Int,
) -> RateLimiterBuilder(a, b, c)

Set the rate limit per second.

pub fn try_build(
  config: RateLimiterBuilder(a, b, c),
) -> Result(RateLimiter(a, b, c), String)

Build the rate limiter, but return an error instead of panicking.

Search Document