Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Guzzle Rate Limiter Middleware Laravel Package

spatie/guzzle-rate-limiter-middleware

Guzzle middleware to rate-limit HTTP requests by requests/second or requests/minute. When the limit is hit, it sleeps until a slot is available. Includes an in-memory store and supports custom persistence for sharing limits across processes.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require spatie/guzzle-rate-limiter-middleware
    

    Add to composer.json if using Guzzle 6/7:

    "require": {
        "guzzlehttp/guzzle": "^7.0"
    }
    
  2. Basic Usage:

    use Spatie\GuzzleRateLimiterMiddleware\RateLimiterMiddleware;
    
    $client = new \GuzzleHttp\Client([
        'middleware' => [
            new RateLimiterMiddleware(10, 60), // 10 requests per 60 seconds
        ],
    ]);
    
  3. First Use Case: Rate-limit API calls to a third-party service (e.g., Twitter API):

    $response = $client->get('https://api.twitter.com/1.1/statuses/user_timeline.json');
    

Implementation Patterns

Common Workflows

  1. Per-Endpoint Rate Limiting: Use middleware stacks for granular control:

    $client = new \GuzzleHttp\Client([
        'middleware' => [
            new RateLimiterMiddleware(5, 60, 'twitter_endpoint'), // Unique key per endpoint
        ],
    ]);
    
  2. Dynamic Rate Limits: Fetch limits from a config file or database:

    $rateLimit = config('services.api.rate_limits.twitter');
    $middleware = new RateLimiterMiddleware($rateLimit['max'], $rateLimit['period']);
    
  3. Retry Logic: Combine with Guzzle’s retry middleware:

    $client = new \GuzzleHttp\Client([
        'middleware' => [
            new RateLimiterMiddleware(3, 10), // 3 requests per 10 seconds
            new \GuzzleHttp\Middleware\RetryMiddleware([
                'max_retries' => 3,
                'delay' => 100,
            ]),
        ],
    ]);
    
  4. Laravel Integration: Use in HTTP clients (Laravel 8+):

    $client = new \GuzzleHttp\Client([
        'base_uri' => 'https://api.example.com',
        'middleware' => [
            new RateLimiterMiddleware(100, 60),
        ],
    ]);
    
    $response = Http::client($client)->get('/endpoint');
    
  5. Async Requests: For async requests (e.g., ReactPHP), use the InMemoryStore or implement a custom driver:

    $store = new \Spatie\GuzzleRateLimiterMiddleware\InMemoryStore();
    $middleware = new RateLimiterMiddleware(10, 60, null, $store);
    

Gotchas and Tips

Pitfalls

  1. Process Isolation:

    • The default InMemoryStore does not work across processes (e.g., queues, cron jobs). Use a shared store (e.g., Redis, database) for distributed systems.
    • Example with Redis:
      $store = new \Spatie\GuzzleRateLimiterMiddleware\RedisStore(
          new \Redis(),
          'rate_limiter'
      );
      
  2. Sleep Overhead:

    • The middleware blocks execution with sleep() when limits are hit. Avoid in long-running scripts or high-throughput systems.
    • For non-blocking behavior, implement a custom driver with async checks (e.g., Redis SETNX + EXPIRE).
  3. Key Collisions:

    • Default key generation uses the full request URI. For APIs with dynamic paths (e.g., /users/{id}), override the key logic:
      $middleware = new RateLimiterMiddleware(10, 60, function ($request) {
          return 'users_' . $request->getUri()->getPath();
      });
      
  4. Testing:

    • Mock the store to simulate rate limits in tests:
      $store = Mockery::mock(\Spatie\GuzzleRateLimiterMiddleware\Store::class);
      $store->shouldReceive('increment')->andReturn(true); // Simulate limit hit
      $middleware = new RateLimiterMiddleware(1, 1, null, $store);
      

Tips

  1. Monitoring:

    • Log rate limit events for observability:
      $middleware = new RateLimiterMiddleware(10, 60);
      $middleware->setLogger(new \Monolog\Logger('rate_limiter'));
      
  2. Burst Handling:

    • Allow bursts by adjusting the period (e.g., 5, 1 for 5 requests per second).
  3. Custom Drivers:

    • Extend \Spatie\GuzzleRateLimiterMiddleware\Store for database-backed stores:
      class DatabaseStore implements Store {
          public function increment(string $key): bool {
              // Custom logic (e.g., MySQL + LUA script)
          }
      }
      
  4. Laravel Caching:

    • Use Laravel’s cache driver for simplicity:
      $store = new \Spatie\GuzzleRateLimiterMiddleware\CacheStore(
          app('cache.store')
      );
      
  5. Debugging:

    • Enable debug mode to log rate limit events:
      $middleware->setDebug(true);
      
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport