limiter

package
v0.0.0-...-aaadb90 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 8, 2026 License: MIT Imports: 6 Imported by: 0

Documentation

Overview

Package limiter provides middleware for rate limiting HTTP requests in Quick.

This middleware controls the number of requests a client can make within a specified time window, helping to prevent abuse, protect APIs from excessive traffic, and improve overall system stability.

Features: - Configurable maximum requests per time window. - Customizable key generator (e.g., per-IP, per-user, etc.). - Flexible expiration time for rate-limited requests. - Custom handler when the request limit is exceeded. - Uses sharded maps for efficient concurrency handling. - Periodic cleanup of expired request records to optimize memory usage.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func New

func New(config Config) func(http.Handler) http.Handler

New creates a middleware constructor that returns a standard http.Handler wrapper.

Usage:

q.Use(limiter.New(limiter.Config{
    Max:        3,
    Expiration: 2 * time.Second,
    KeyGenerator: func(c *quick.Ctx) string {
        // Return IP without port, or a fixed test key.
        return "testKey"
    },
    LimitReached: func(c *quick.Ctx) error {
        return c.Status(http.StatusTooManyRequests).SendString("Too many requests")
    },
}))

The returned function integrates with Quick's middleware chain and enforces rate limits.

Types

type Config

type Config struct {
	Max          int                     // Maximum requests allowed in the time window
	Expiration   time.Duration           // Time window for rate limiting
	KeyGenerator func(*quick.Ctx) string // Function to generate a unique key per client
	LimitReached func(*quick.Ctx) error  // Function executed when rate limit is exceeded
}

Config defines the rate limiting configuration.

Max: maximum number of requests allowed within the expiration window. Expiration: duration before the request counter resets. KeyGenerator: function to generate a unique key for each client (e.g., IP-based). LimitReached: function called when the client exceeds the request limit.

type RateLimiter

type RateLimiter struct {
	// contains filtered or unexported fields
}

RateLimiter manages all rate limiting logic, storing request counters across multiple shards.

Example

ExampleRateLimiter demonstrates basic rate limiting configuration. This example shows:

  • Setting a global rate limit (3 requests per 10 seconds)
  • Using a fixed client key for testing
  • Custom response for rate-limited requests
  • Integration with Quick framework
q := quick.New()

// Configure rate limiting with:
// - Max: 3 requests per window
// - Window: 10 seconds
// - Fixed client key for testing
// - Custom rate limit response
q.Use(New(Config{
	Max:        3,
	Expiration: 10 * time.Second,
	KeyGenerator: func(c *quick.Ctx) string {
		return "test-client" // Fixed key to simulate a single user/IP
	},
	LimitReached: func(c *quick.Ctx) error {
		// Print the limit exceeded message for demonstration
		response := map[string]string{
			"error":       "Too many requests",
			"message":     "You have exceeded the request limit. Please wait 10 seconds and try again.",
			"retry_after": "10s",
		}
		fmt.Println("Rate Limit Exceeded:", response) // <-- This line is essential for Output
		c.Set("Content-Type", "application/json")
		c.Set("Retry-After", "10")
		return c.Status(quick.StatusTooManyRequests).JSON(response)
	},
}))

// Define the test route
q.Get("/", func(c *quick.Ctx) error {
	return c.JSON(map[string]string{
		"msg": "Quick in action!",
	})
})

// Simulate 5 requests (rate limit is 3)
for i := 0; i < 3; i++ {
	res, _ := q.Qtest(quick.QuickTestOptions{
		Method: quick.MethodGet,
		URI:    "/",
	})
	fmt.Println(res.BodyStr())
}
Output:
{"msg":"Quick in action!"}
{"msg":"Quick in action!"}
Rate Limit Exceeded: map[error:Too many requests message:You have exceeded the request limit. Please wait 10 seconds and try again. retry_after:10s]
{"error":"Too many requests","message":"You have exceeded the request limit. Please wait 10 seconds and try again.","retry_after":"10s"}
Example (Group)

This function is named ExampleRateLimiter_group() it with the Examples type.

// Create a new Quick instance
q := quick.New()

// Rate Limiter Middleware
limiterMiddleware := New(Config{
	// Maximum 5 requests allowed per IP address within a 10-second window
	Max: 3,
	// The limit resets every 10 seconds
	Expiration: 10 * time.Second,
	// Use the client's IP address as the unique key to track rate limits
	KeyGenerator: func(c *quick.Ctx) string {
		return c.RemoteIP()
	},
	// If the rate limit is exceeded, send an error message and instructions
	LimitReached: func(c *quick.Ctx) error {
		// Set content type to JSON
		c.Set("Content-Type", "application/json")
		// Set the Retry-After header to indicate how long the client should wait before retrying
		c.Set("Retry-After", "10") // The client should wait 10 seconds before retrying
		// Response structure
		response := map[string]string{
			"error":       "Too many requests",
			"message":     "You have exceeded the request limit. Please wait 10 seconds and try again.",
			"retry_after": "10s",
		}

		// Log to verify that the rate limit exceeded response is being sent
		fmt.Println("Rate Limit Exceeded:", response)

		// Return the response with HTTP status 429 (Too Many Requests)
		return c.Status(quick.StatusTooManyRequests).JSON(response)
	},
})

// Create an API group with rate limit middleware
api := q.Group("/v1")
// Apply the rate limiter middleware to the /api group
api.Use(limiterMiddleware)

// Define route /api/users that responds with a list of users
api.Get("/users", func(c *quick.Ctx) error {
	return c.JSON(map[string]string{"msg": "list of users"})
})

// Define route without rate limit
// This route is not affected by the rate limiter
q.Get("/", func(c *quick.Ctx) error {
	return c.JSON(map[string]string{"msg": "Quick in action!"})
})

// Functionality test using QuickTest (simulates a request for the protected route)
for i := 0; i < 4; i++ { // Send more requests than the limit (3) to test the block
	res, _ := q.Qtest(quick.QuickTestOptions{
		Method: quick.MethodGet,
		URI:    "/v1/users",
	})
	fmt.Println(res.BodyStr())
}
Output:
{"msg":"list of users"}
{"msg":"list of users"}
{"msg":"list of users"}
Rate Limit Exceeded: map[error:Too many requests message:You have exceeded the request limit. Please wait 10 seconds and try again. retry_after:10s]
{"error":"Too many requests","message":"You have exceeded the request limit. Please wait 10 seconds and try again.","retry_after":"10s"}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL