Categorygithub.com/didip/tollbooth
modulepackage
1.0.0
Repository: https://github.com/didip/tollbooth.git
Documentation: pkg.go.dev

# README

GoDoc license

Tollbooth

This is a generic middleware to rate-limit HTTP requests.

NOTE 1: This library is considered finished.

NOTE 2: In the coming weeks, I will be removing thirdparty modules and moving them to their own dedicated repos.

Five Minutes Tutorial

package main

import (
    "github.com/didip/tollbooth"
    "net/http"
    "time"
)

func HelloHandler(w http.ResponseWriter, req *http.Request) {
    w.Write([]byte("Hello, World!"))
}

func main() {
    // Create a request limiter per handler.
    http.Handle("/", tollbooth.LimitFuncHandler(tollbooth.NewLimiter(1, time.Second), HelloHandler))
    http.ListenAndServe(":12345", nil)
}

Features

  1. Rate-limit by request's remote IP, path, methods, custom headers, & basic auth usernames.

    limiter := tollbooth.NewLimiter(1, time.Second)
    
    // or create a limiter with expirable token buckets
    // This setting means:
    // create a 1 request/second limiter and
    // every token bucket in it will expire 1 hour after it was initially set.
    limiter = tollbooth.NewLimiterExpiringBuckets(1, time.Second, time.Hour, 0)
    
    // Configure list of places to look for IP address.
    // By default it's: "RemoteAddr", "X-Forwarded-For", "X-Real-IP"
    // If your application is behind a proxy, set "X-Forwarded-For" first.
    limiter.IPLookups = []string{"RemoteAddr", "X-Forwarded-For", "X-Real-IP"}
    
    // Add a function to be called when a request is rejected.
    limiter.RejectFunc = func() { fmt.Println("A request was rejected") }
    
    // Limit only GET and POST requests.
    limiter.Methods = []string{"GET", "POST"}
    
    // Limit request headers containing certain values.
    // Typically, you prefetched these values from the database.
    limiter.Headers = make(map[string][]string)
    limiter.Headers["X-Access-Token"] = []string{"abc123", "xyz098"}
    
    // Limit based on basic auth usernames.
    // Typically, you prefetched these values from the database.
    limiter.BasicAuthUsers = []string{"bob", "joe", "didip"}
    
  2. Each request handler can be rate-limited individually.

  3. Compose your own middleware by using LimitByKeys().

  4. Tollbooth does not require external storage since it uses an algorithm called Token Bucket (Go library: golang.org/x/time/rate).

Other Web Frameworks

Sometimes, other frameworks require a little bit of shim to use Tollbooth. These shims below are contributed by the community, so I make no promises on how well they work. The one I am familiar with are: Chi, Gin, and Negroni.

# Packages

Package config provides data structure to configure rate-limiter.
Package errors provide data structure for errors.
Package libstring provides various string related functions.

# Functions

BuildKeys generates a slice of keys to rate-limit by given config and request structs.
LimitByKeys keeps track number of request made by keys separated by pipe.
LimitByKeysWithCustomTokenBucketTTL keeps track number of request made by keys separated by pipe.
LimitByRequest builds keys based on http.Request struct, loops through all the keys, and check if any one of them returns HTTPError.
LimitFuncHandler is a middleware that performs rate-limiting given request handler function.
LimitHandler is a middleware that performs rate-limiting given http.Handler struct.
NewLimiter is a convenience function to config.NewLimiter.
No description provided by the author
SetResponseHeaders configures X-Rate-Limit-Limit and X-Rate-Limit-Duration.