Rate Limiting

Rate limiting protects your application from abuse by restricting how many requests a client can make within a time window. Nimbus provides middleware.RateLimit() as an in-memory rate limiter you can apply globally or to specific route groups.

Basic usage

The RateLimit middleware takes three parameters: the request limit, the time window, and a key function that identifies each client:

app.Router.Use(middleware.RateLimit(100, time.Minute, func(r *http.Request) string {
    return r.RemoteAddr
}))

This allows 100 requests per minute per IP address. When the limit is exceeded, the middleware returns a 429 Too Many Requests JSON response.

Parameters

  • limit int — Maximum number of requests allowed in the window.
  • window time.Duration — The time period for the limit (e.g. time.Minute, time.Hour).
  • keyFn func(*http.Request) string — Extracts a unique key per client. If it returns an empty string, RemoteAddr is used as fallback.

Per-IP limiting

The most common approach is to rate limit by client IP address:

app.Router.Use(middleware.RateLimit(60, time.Minute, func(r *http.Request) string {
    return r.RemoteAddr
}))

Custom key functions

You can rate limit by any identifier — for example, by API key or authenticated user ID:

// Rate limit by API key
app.Router.Use(middleware.RateLimit(1000, time.Hour, func(r *http.Request) string {
    return r.Header.Get("X-API-Key")
}))

// Rate limit by authenticated user
app.Router.Use(middleware.RateLimit(200, time.Minute, func(r *http.Request) string {
    user := auth.UserFromContext(r.Context())
    if user != nil {
        return user.GetID()
    }
    return r.RemoteAddr
}))

Rate limiting specific routes

Apply stricter limits to sensitive endpoints like login or password reset:

authGroup := app.Router.Group("/auth")
authGroup.Use(middleware.RateLimit(5, time.Minute, func(r *http.Request) string {
    return r.RemoteAddr
}))
authGroup.Post("/login", HandleLogin)
authGroup.Post("/reset-password", HandlePasswordReset)

Response on limit exceeded

When a client exceeds the limit, Nimbus returns a JSON response with HTTP status 429:

HTTP/1.1 429 Too Many Requests
Content-Type: application/json

{"error": "rate limit exceeded"}

How it works internally

The rate limiter stores a counter and window start time per key in memory. When a request arrives:

  • If the key is new or the window has expired, the counter resets to 1.
  • If the counter is below the limit, it increments and the request proceeds.
  • If the counter has reached the limit, the request is rejected with 429.

This is an in-memory implementation suitable for single-server deployments. For distributed systems, consider implementing a custom middleware backed by Redis or a similar shared store.