Skip to content

Middleware

Rate Limiter

Limit request rates per client, per API key, or globally with a token bucket.

RateLimiter refuses requests that arrive faster than a set rate, answering 429 Too Many Requests. It uses a token bucket: each request spends one token, and tokens refill at a steady rate up to a maximum burst.

For most public APIs, limit per client IP:

app.Use(middleware.IPRateLimiter(20, 40)) // 20 requests per second, bursts up to 40

Configure trusted proxies first when the app runs behind a load balancer. Otherwise every request shares the load balancer’s IP and one bucket.

Constructor One bucket per
IPRateLimiter(rate, burst) Client IP, from c.IP()
RateLimiter(config) with KeyGenerator Whatever the function returns, such as an API key or user ID
RateLimiter() with no arguments Nothing: one bucket shared by every request
app.Use(middleware.RateLimiter(middleware.RateLimiterConfig{
Rate: 30, // tokens per second
Capacity: 60, // maximum burst
KeyGenerator: func(c *zinc.Context) string {
return c.GetHeader("X-API-Key")
},
LimitReachedHandler: func(c *zinc.Context) error {
c.SetHeader("Retry-After", "1")
return c.Status(zinc.StatusTooManyRequests).JSON(zinc.Map{"error": "rate limit exceeded"})
},
}))

When you pass a config, set both Rate and Capacity. They default to 0, which rejects every request.

Field Default Meaning
Rate 10 without a config, else required Tokens added per second
Capacity 10 without a config, else required Largest burst
KeyGenerator none Returns the bucket key for a request
IPLookup none Returns a client identity; used when KeyGenerator is not set
StatusCode 429 Status when the limit is hit
LimitReachedHandler plain-text 429 Writes the response when the limit is hit

Keys are chosen in this order: KeyGenerator, then IPLookup, then one global bucket.

Each distinct key keeps its bucket for the life of the process. With keys from a bounded set, such as your API keys or user IDs, that is fine. Per-IP limiting on public traffic grows with the number of distinct clients. Restart periodically, or enforce the limit at your load balancer or API gateway.

Keyed limiters retain at most MaxKeys buckets (default 10,000) with keys of at most MaxKeyBytes bytes (default 256). When full, new keys receive the configured limit response; existing quotas remain in force. Idle buckets expire after IdleTTL (default five minutes), once their tokens have fully replenished. Cleanup is bounded and runs during requests. Choose the capacity for your expected client population; saturation deliberately denies new clients rather than granting fresh quotas through eviction.

Zero Rate and Capacity use 10 tokens/second and a burst of 10. Invalid negative or non-finite settings panic during construction. StatusCode defaults to 429 and is respected by the default rejection handler. Now can supply a deterministic clock for tests.