Rate Limiter Utility

The RateLimiterUtil has been refactored to use dependency injection instead of creating new instances every time. This provides better performance and follows Laravel's best practices.

Configuration

The rate limiter utility is configured in config/lara-util-x.php:

'rate_limiting' => [
    'default_max_attempts' => 60,
    'default_decay_minutes' => 1,
    'cache_prefix' => 'rate_limit:',
    'defaults' => [
        'api' => [
            'max_attempts' => 60,
            'decay_minutes' => 1,
        ],
        'auth' => [
            'max_attempts' => 5,
            'decay_minutes' => 15,
        ],
        'download' => [
            'max_attempts' => 3,
            'decay_minutes' => 1,
        ],
    ],
],

Usage Examples

1. Dependency Injection in Controllers

<?php

namespace App\Http\Controllers;

use LaraUtilX\Utilities\RateLimiterUtil;

class MyController extends Controller
{
    private RateLimiterUtil $rateLimiter;

    public function __construct(RateLimiterUtil $rateLimiter)
    {
        $this->rateLimiter = $rateLimiter;
    }

    public function someAction(Request $request)
    {
        $key = 'user_action_' . $request->user()->id;

        if ($this->rateLimiter->attempt($key, 5, 1)) {
            // Action allowed
            return response()->json(['message' => 'Success']);
        }

        // Rate limit exceeded
        return response()->json(['error' => 'Too many attempts'], 429);
    }
}

2. Using the Container Directly

public function someMethod(Request $request)
{
    $rateLimiter = app(RateLimiterUtil::class);

    if ($rateLimiter->attempt('api_call', 10, 1)) {
        // Proceed with API call
    }
}

3. Using Configuration-Based Rate Limiting

public function apiAction(Request $request)
{
    $config = config('lara-util-x.rate_limiting');
    $apiSettings = $config['defaults']['api'];

    $key = 'api_' . $request->ip();

    if ($this->rateLimiter->attempt($key, $apiSettings['max_attempts'], $apiSettings['decay_minutes'])) {
        // API call allowed
    }
}

Available Methods

attempt(string $key, int $maxAttempts, int $decayMinutes): bool

Attempts to hit the rate limiter and returns true if successful.

attempts(string $key): int

Gets the number of attempts for the given key.

remaining(string $key, int $maxAttempts): int

Gets the number of remaining attempts for the given key.

clear(string $key): void

Clears the hits and lockout timer for the given key.

availableIn(string $key): int

Gets the number of seconds until the key is accessible again.

tooManyAttempts(string $key, int $maxAttempts): bool

Determines if the given key has been accessed too many times.

hit(string $key, int $decaySeconds = 60): int

Increments the counter for a given key for a given decay time.

getRateLimiter(): RateLimiter

Gets the underlying Laravel RateLimiter instance.

Benefits of Dependency Injection

  1. Performance: No new instances created on every call
  2. Testability: Easy to mock in unit tests
  3. Consistency: Follows Laravel's dependency injection patterns
  4. Configuration: Centralized configuration management
  5. Reusability: Single instance shared across the application

Testing

public function testRateLimiting()
{
    $rateLimiter = app(RateLimiterUtil::class);

    // First attempt should succeed
    $this->assertTrue($rateLimiter->attempt('test_key', 1, 1));

    // Second attempt should fail
    $this->assertFalse($rateLimiter->attempt('test_key', 1, 1));
}