How to Implement Rate Limiting in Gorig's HTTP Server: Using the Built-In Debounce Middleware

Gorig implements rate limiting through a built-in Debounce middleware in the httpx package that throttles requests per IP or authenticated user using a high-performance sharded in-memory map with a default 200ms window.

Gorig provides a production-ready solution for request throttling without requiring external dependencies. The framework automatically configures rate limiting during server startup using the Debounce middleware found in httpx/mid.debounce.go, which integrates directly with the Gin engine to protect your endpoints from rapid-fire requests.

Understanding Gorig's Debounce Middleware

The Debounce middleware acts as a request deduplication layer that prevents clients from flooding your server with identical calls within a configurable time window. According to the Gorig source code, this middleware constructs a unique key using either <path>:id:<userId> for authenticated users or <path>:ip:<clientIP> for anonymous clients, storing timestamps in a specialized ShardedRequestMap structure.

The implementation resides in [httpx/mid.debounce.go](https://github.com/jom-io/gorig/blob/master/httpx/mid.debounce.go) and automatically attaches to the global Gin engine in [httpx/serv.go](https://github.com/jom-io/gorig/blob/master/httpx/serv.go#L78-L83) during server initialization (lines 78-83):

gEngine.Use(Debounce(200 * time.Millisecond))

This configuration applies a 200-millisecond throttle window by default, meaning subsequent identical requests from the same client within that timeframe receive an immediate 429 Too Many Requests response via response.ErrorTooManyRequests.

How Rate Limiting Works Under the Hood

When an HTTP request enters the system, the middleware executes a multi-step validation process:

  1. Whitelist Check: The middleware first verifies if the requested path exists in the internal whiteList slice populated via DebouceAw(). Whitelisted routes bypass all throttling logic.

  2. Client Identification: The system extracts a unique identifier using GetTokenByCtx (defined in httpx/mid.sign.go, lines 108-119) to retrieve the authenticated user ID. If authentication is absent, the client's IP address serves as the fallback identifier.

  3. Sharded Map Lookup: The unique key queries the ShardedRequestMap, which distributes entries across 32 shards—each protected by its own RWMutex. This architecture minimizes lock contention and enables near lock-free lookups for high-throughput scenarios.

  4. Expiration Logic: If the key exists and the elapsed time remains below the configured duration, the middleware aborts the request chain with HTTP 429. Otherwise, it records the current timestamp and permits the request to proceed.

  5. Memory Management: A background routine automatically clears individual shards when they exceed approximately 2 MiB, preventing unbounded memory growth in long-running services.

Implementation Examples

Default Configuration (200ms)

No additional code is required to enable basic rate limiting. The framework automatically registers the middleware during server boot in httpx/serv.go:

// Server starts with default 200ms debounce automatically
// All routes protected except those explicitly whitelisted

Custom Debounce Intervals

Override the default window by re-registering the middleware with a custom time.Duration. This approach replaces the automatic configuration with your specified interval:

import "github.com/jom-io/gorig/httpx"
import "time"

func init() {
    // Extend throttle window to 500ms for high-latency operations
    httpx.RegisterRouterMid(func(g *gin.RouterGroup, mids ...gin.HandlerFunc) *gin.RouterGroup {
        g.Use(httpx.Debounce(500 * time.Millisecond))
        return g
    })
}

Whitelisting Specific Routes

Exclude health checks, metrics endpoints, or public APIs from rate limiting using the DebouceAw function (note the function naming as implemented in the source):

import "github.com/jom-io/gorig/httpx"

func init() {
    // These paths bypass the sharded request map entirely
    httpx.DebouceAw("/health", "/metrics", "/api/public/status")
}

Disabling Rate Limiting for Testing

Integration tests often require rapid sequential requests. Globally disable the middleware using DebounceDisable(), which sets the internal enable flag to false:

import "github.com/jom-io/gorig/httpx"
import "testing"

func TestMain(m *testing.M) {
    // Disable throttle for entire test suite
    httpx.DebounceDisable()
    m.Run()
}

Custom Router Integration

For applications using manually instantiated Gin engines rather than the global server, apply the middleware directly:

router := gin.New()
// Apply 300ms debounce to this specific router instance
router.Use(httpx.Debounce(300 * time.Millisecond))
router.GET("/api/data", func(c *gin.Context) {
    // Handler logic executes only if request passes throttle check
})

Key Source Files and Architecture

Understanding the following files enables advanced customization of Gorig's rate limiting behavior:

  • httpx/mid.debounce.go: Contains the complete Debounce implementation including the ShardedRequestMap struct, Debounce(duration) constructor, DebouceAw() whitelist manager, and DebounceDisable() global toggle.

  • httpx/serv.go: Server bootstrap code that registers the default middleware (lines 78-83). Modify this file to change framework-wide defaults.

  • httpx/mid.sign.go: Defines GetTokenByCtx (lines 108-119), the helper function extracting user IDs for authenticated rate limiting.

  • apix/response/response.go: Implements ErrorTooManyRequests, the HTTP 429 response generator used when throttling triggers.

Summary

  • Gorig's rate limiting relies on the Debounce middleware located in httpx/mid.debounce.go, utilizing a sharded in-memory map for high-performance request deduplication.
  • The default configuration applies a 200ms throttle window to all routes, automatically registered during server startup in httpx/serv.go.
  • Client identification prioritizes authenticated user IDs via GetTokenByCtx, falling back to IP addresses for unauthenticated requests.
  • The sharded architecture (32 shards with independent RWMutexes) minimizes lock contention, while automatic cleanup prevents memory leaks at scale.
  • Whitelist management via DebouceAw() and global disable via DebounceDisable() provide flexible control for health checks, metrics, and testing environments.

Frequently Asked Questions

What is the default rate limit window in Gorig?

The default throttle duration is 200 milliseconds, configured in httpx/serv.go during engine initialization. This value strikes a balance between user experience and server protection for most web applications.

How does Gorig differentiate between authenticated and unauthenticated users for rate limiting?

The middleware attempts to extract a user ID first by calling GetTokenByCtx from the request context (as defined in httpx/mid.sign.go). If no authentication token exists, it falls back to the client's IP address, creating keys in the format <path>:ip:<clientIP> rather than <path>:id:<userId>.

Can I disable rate limiting for specific API endpoints while keeping it active for others?

Yes. Use the DebouceAw() function to append specific paths to the internal whiteList slice. Routes matching these patterns bypass the ShardedRequestMap lookup entirely and execute without throttle checks.

What HTTP status code does Gorig return when rate limiting triggers?

When a request exceeds the configured rate limit, Gorig responds with HTTP 429 Too Many Requests using the ErrorTooManyRequests function from apix/response/response.go. This standard status code signals clients to implement exponential backoff strategies.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →