Documentation
¶
Overview ¶
Package ratelimit provides middleware for token bucket rate limiting per client.
This middleware implements rate limiting using a token bucket algorithm to control the rate of requests from clients. It supports per-IP, per-user, or custom key-based rate limiting with configurable rate and burst limits.
Basic Usage ¶
import "rivaas.dev/middleware/ratelimit"
r := router.MustNew()
r.Use(ratelimit.New(
ratelimit.WithRequestsPerSecond(100),
ratelimit.WithBurst(20),
))
Rate Limiting Strategies ¶
The middleware supports different rate limiting strategies:
- Per IP: Limit requests per client IP address (default)
- Per User: Limit requests per authenticated user
- Custom Key: Use a custom KeyFunc to determine the rate limit key
Configuration Options ¶
- RequestsPerSecond: Average rate of requests allowed (required)
- Burst: Maximum burst size (default: same as RequestsPerSecond)
- KeyFunc: Function to determine rate limit key (default: per IP)
- SkipPaths: Paths to exclude from rate limiting (e.g., /health)
- Logger: Optional logger for rate limit events
- OnLimitExceeded: Custom handler when rate limit is exceeded
Custom Key Function ¶
import "rivaas.dev/middleware/ratelimit"
r.Use(ratelimit.New(
ratelimit.WithRequestsPerSecond(100),
ratelimit.WithKeyFunc(func(c *router.Context) string {
// Rate limit per user ID
return c.Param("user_id")
}),
))
Rate Limit Headers ¶
The middleware sets standard rate limit headers in responses:
- X-RateLimit-Limit: Maximum requests allowed per window
- X-RateLimit-Remaining: Remaining requests in current window
- X-RateLimit-Reset: Unix timestamp when the rate limit resets
The token bucket algorithm supports concurrent access.
Package ratelimit provides middleware for rate limiting HTTP requests using configurable stores (in-memory, Redis, etc.) and token bucket algorithm.
Index ¶
- func New(opts ...Option) router.HandlerFunc
- func PerRoute(m router.HandlerFunc) router.HandlerFunc
- func WithSlidingWindow(sw SlidingWindow, opts CommonOptions) router.HandlerFunc
- func WithTokenBucket(tb TokenBucket, opts CommonOptions) router.HandlerFunc
- type CommonOptions
- type InMemoryStore
- type InMemoryTokenBucketStore
- type KeyFunc
- type Meta
- type Option
- func WithBurst(burst int) Option
- func WithCleanupInterval(interval time.Duration) Option
- func WithHandler(fn func(*router.Context)) Option
- func WithKeyFunc(fn func(*router.Context) string) Option
- func WithLimiterTTL(ttl time.Duration) Option
- func WithLogger(logger *slog.Logger) Option
- func WithRequestsPerSecond(rps int) Option
- type SlidingWindow
- type TokenBucket
- type TokenBucketStore
- type WindowStore
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func New ¶
func New(opts ...Option) router.HandlerFunc
New creates a token bucket rate limiter middleware using functional options. Defaults: 100 requests/second, burst of 20, rate limit by IP.
Example:
r.Use(ratelimit.New(
ratelimit.WithRequestsPerSecond(50),
ratelimit.WithBurst(10),
))
func PerRoute ¶
func PerRoute(m router.HandlerFunc) router.HandlerFunc
PerRoute wraps a rate limiter middleware for per-route application. This allows different rate limits for different routes.
Example:
r.GET("/expensive", handler, ratelimit.PerRoute(
ratelimit.WithSlidingWindow(...),
))
func WithSlidingWindow ¶
func WithSlidingWindow(sw SlidingWindow, opts CommonOptions) router.HandlerFunc
WithSlidingWindow creates a sliding window rate limiter middleware.
func WithTokenBucket ¶
func WithTokenBucket(tb TokenBucket, opts CommonOptions) router.HandlerFunc
WithTokenBucket creates a token bucket rate limiter middleware.
Types ¶
type CommonOptions ¶
type CommonOptions struct {
Key KeyFunc // Function to derive rate limit key
Headers bool // Emit RateLimit-* headers (IETF draft)
Enforce bool // true = block on exceed (429), false = report-only
OnExceeded func(*router.Context, Meta) // Callback when limit exceeded
// contains filtered or unexported fields
}
CommonOptions contains shared configuration for all rate limiters.
type InMemoryStore ¶
type InMemoryStore struct {
// contains filtered or unexported fields
}
InMemoryStore implements in-memory sliding window storage.
func NewInMemoryStore ¶
func NewInMemoryStore() *InMemoryStore
NewInMemoryStore creates a new in-memory sliding window store.
type InMemoryTokenBucketStore ¶
type InMemoryTokenBucketStore struct {
// contains filtered or unexported fields
}
InMemoryTokenBucketStore implements in-memory token bucket storage. This is the default store implementation used by the token bucket rate limiter.
func NewInMemoryTokenBucketStore ¶
func NewInMemoryTokenBucketStore(rate, burst int) *InMemoryTokenBucketStore
NewInMemoryTokenBucketStore creates a new in-memory token bucket store. This is exposed to allow custom configuration of the default store.
Example:
store := ratelimit.NewInMemoryTokenBucketStore(100, 20)
r.Use(ratelimit.WithTokenBucket(
ratelimit.TokenBucket{Rate: 100, Burst: 20, Store: store},
ratelimit.CommonOptions{},
))
type KeyFunc ¶
KeyFunc determines the rate limit key for a request (e.g., per IP, per user, per route).
type Meta ¶
type Meta struct {
Limit int // Rate limit (requests per window)
Remaining int // Remaining requests in current window
ResetSeconds int // Seconds until window reset
Window time.Duration // Window duration
Key string // Rate limit key (e.g., "ip:192.168.1.1")
Route string // Matched route pattern
Method string // HTTP method
ClientIP string // Client IP address
}
Meta contains rate limit metadata for callbacks and logging.
type Option ¶
type Option func(*config)
Option defines functional options for rate limit middleware configuration.
func WithBurst ¶
WithBurst sets the maximum burst size. Burst allows clients to make multiple requests instantly up to this limit. Default: 20 requests
Example:
ratelimit.New(ratelimit.WithBurst(10))
func WithCleanupInterval ¶
WithCleanupInterval sets how often to clean up expired limiters. Default: 1 minute
func WithHandler ¶
WithHandler sets a custom handler for when rate limit is exceeded. Default: Returns 429 Too Many Requests with JSON error
Example:
ratelimit.New(
ratelimit.WithHandler(func(c *router.Context) {
c.String(http.StatusTooManyRequests, "Slow down! Try again in a minute.")
}),
)
func WithKeyFunc ¶
WithKeyFunc sets a custom function to extract the rate limit key from requests. Common use cases:
- Per-IP limiting: Use client IP (default)
- Per-user limiting: Use user ID from authentication
- Per-API key limiting: Use API key from header
Example:
ratelimit.New(
ratelimit.WithKeyFunc(func(c *router.Context) string {
// Rate limit by user ID from auth token
return c.Request.Header.Get("X-User-ID")
}),
)
func WithLimiterTTL ¶
WithLimiterTTL sets how long to keep inactive limiters before cleanup. Default: 5 minutes
func WithLogger ¶
WithLogger sets the slog.Logger for error logging. If not provided, errors will be silently ignored.
Uses the standard library's log/slog package for structured logging:
import "log/slog" logger := slog.New(slog.NewJSONHandler(os.Stdout, nil)) ratelimit.New(ratelimit.WithLogger(logger))
Example:
import "log/slog" logger := slog.New(slog.NewJSONHandler(os.Stdout, nil)) r.Use(ratelimit.New(ratelimit.WithLogger(logger)))
func WithRequestsPerSecond ¶
WithRequestsPerSecond sets the number of requests allowed per second. Default: 100 requests/second
Example:
ratelimit.New(ratelimit.WithRequestsPerSecond(50))
type SlidingWindow ¶
type SlidingWindow struct {
Window time.Duration // Fixed window duration (e.g., 1 minute)
Limit int // Requests per window
Store WindowStore // Storage backend (in-memory, Redis, etc.)
}
SlidingWindow implements sliding window rate limiting. Uses two fixed windows (current + previous) for accurate counting.
type TokenBucket ¶
type TokenBucket struct {
Rate int // Tokens per second
Burst int // Maximum tokens (burst capacity)
Store TokenBucketStore // Optional custom store (defaults to in-memory)
}
TokenBucket implements token bucket rate limiting. Allows bursts up to Burst size, refills at Rate tokens per second.
type TokenBucketStore ¶
type TokenBucketStore interface {
// Allow checks if a request is allowed for the given key.
// Returns (allowed, remaining tokens, reset time in seconds).
Allow(key string, now time.Time) (allowed bool, remaining, resetSeconds int)
}
TokenBucketStore provides storage for token bucket rate limiting. This allows custom implementations (e.g., Redis-backed) for distributed systems.
type WindowStore ¶
type WindowStore interface {
// GetCounts returns (current count, previous count, window start unix time, error).
GetCounts(ctx context.Context, key string, window time.Duration) (int, int, int64, error)
// Incr increments the current window count.
Incr(ctx context.Context, key string, window time.Duration) error
}
WindowStore provides storage for sliding window rate limiting.