# ratelimit

```go
import "apistock.dev/ratelimit"
```

Package ratelimit provides token-bucket rate limiting keyed by a string (an IP address, account or API key): the [Taker](#Taker) interface, an in-memory [Limiter](#Limiter), and HTTP middleware.

The in-memory limiter is per process: behind several instances each one enforces its own limit. apistock.dev/modules/ratelimitpg implements [Taker](#Taker) with limits shared across instances (ADR-0052).

Stability: pre-1.0 (ADR-0015).

## Constants

### const DefaultIdleTTL, …

```go
const (
	DefaultIdleTTL = 10 * time.Minute
	DefaultMaxKeys = 100_000
)
```

Defaults for [New](#New).

## Variables

### var ErrEmptyKey

```go
var ErrEmptyKey = errors.New("ratelimit: empty key")
```

ErrEmptyKey reports a request without a key.

## Functions

### func ByRemoteIP

```go
func ByRemoteIP(r *http.Request) string
```

ByRemoteIP keys requests by the connection's remote IP. Behind a proxy, run trusted-proxy middleware first so RemoteAddr holds the client address.

### func Middleware

```go
func Middleware(l Taker, key KeyFunc, onLimit http.Handler) func(http.Handler) http.Handler
```

Middleware limits requests with l. Limited requests receive onLimit, or a 429 application/problem+json response with a Retry-After header when onLimit is nil. When l can't decide, the request proceeds.

## Types

### type Decision

```go
type Decision struct {
	Allowed bool
	// RetryAfter is how long until a request may proceed, when not allowed.
	RetryAfter time.Duration
}
```

Decision is the outcome of one request against a limit.

### type KeyFunc

```go
type KeyFunc func(r *http.Request) string
```

KeyFunc extracts the rate-limit key from a request. An empty key skips limiting for that request.

### type Limit

```go
type Limit struct {
	PerSecond float64
	Burst     int
}
```

Limit is a token bucket: PerSecond requests on average, with bursts of up to Burst.

#### func Per

```go
func Per(n int, window time.Duration) Limit
```

Per returns the limit of n requests per window, all of which may arrive at once.

#### func (Limit) Valid

```go
func (l Limit) Valid() bool
```

Valid reports whether l allows any request.

### type Limiter

```go
type Limiter struct {
	// contains filtered or unexported fields
}
```

A Limiter tracks one token bucket per key. It is safe for concurrent use.

#### func New

```go
func New(perSecond float64, burst int, opts ...Option) *Limiter
```

New returns a limiter allowing perSecond requests per key on average, with bursts of up to burst requests.

#### func (*Limiter) Allow

```go
func (l *Limiter) Allow(key string) (ok bool, retryAfter time.Duration)
```

Allow reports whether a request for key may proceed. When it may not, retryAfter is how long until one token is available.

#### func (*Limiter) Take

```go
func (l *Limiter) Take(_ context.Context, key string) (Decision, error)
```

Take implements [Taker](#Taker) with [Limiter.Allow](#Limiter.Allow); it never fails for a non-empty key.

### type Option

```go
type Option interface {
	// contains filtered or unexported methods
}
```

An Option configures a [Limiter](#Limiter).

#### func WithClock

```go
func WithClock(now func() time.Time) Option
```

WithClock sets the time source, for tests.

#### func WithIdleTTL

```go
func WithIdleTTL(d time.Duration) Option
```

WithIdleTTL sets how long an unused key is remembered. Default: [DefaultIdleTTL](#DefaultIdleTTL).

#### func WithMaxKeys

```go
func WithMaxKeys(n int) Option
```

WithMaxKeys bounds memory use. When the limit is reached and no idle keys can be evicted, new keys are allowed without tracking (fail open), so a flood of distinct keys can't lock out all clients. Default: [DefaultMaxKeys](#DefaultMaxKeys).

### type Taker

```go
type Taker interface {
	Take(ctx context.Context, key string) (Decision, error)
}
```

A Taker decides whether a request for key may proceed. An error means the limiter couldn't decide, and callers allow the request: implementations that can fail handle their own fallback.

