RateLimitExceededException

Overview

RateLimitExceededException is a custom exception class in the Midnite81\Guardian package. This exception is used to signal that a rate limit has been exceeded, particularly when interacting with external APIs or services within a Guardian-protected context.

Class Details

  • Namespace: Midnite81\Guardian\Exceptions

  • Extends: Exception

Purpose

The primary purpose of this exception is to allow developers to integrate external rate limiting information with Guardian's rate limiting system. When thrown inside a closure passed to Guardian's send() method, it enables Guardian to manage rate limiting for external services consistently with its internal mechanisms.

Properties

  • protected DateTimeImmutable $retryAfter: Stores the time when the client can retry the request.

Constructor

public function __construct(mixed $retryAfter, string $message = '', int $code = 0, ?Exception $previous = null)

The constructor takes a $retryAfter parameter, which can be:

  • A DateTimeImmutable object

  • An integer (representing seconds)

  • A string (either an HTTP-date or seconds)

Methods

getRetryAfter

public function getRetryAfter(): DateTimeImmutable

Returns a DateTimeImmutable object representing when the client can retry the request.

Usage

This exception should be thrown by the user inside the closure passed to Guardian's send() method, particularly when handling rate limits from external APIs or services.

Example:

use Midnite81\Guardian\Exceptions\RateLimitExceededException;
use GuzzleHttp\Exception\ClientException;

$guardian->send(function () use ($httpClient) {
    try {
        $response = $httpClient->get('https://api.example.com/endpoint');
        return $response->getBody()->getContents();
    } catch (ClientException $e) {
        if ($e->getResponse()->getStatusCode() === 429) {
            $retryAfter = $e->getResponse()->getHeaderLine('Retry-After');
            throw new RateLimitExceededException($retryAfter, 'Rate limit exceeded by external API');
        }
        // Handle other client exceptions...
        throw $e;
    }
});

Integration with Guardian

When this exception is thrown inside the closure passed to Guardian::send(), Guardian will catch it and handle the rate limiting accordingly. This allows Guardian to manage rate limits for external services in the same way it manages internal rate limits.

Best Practices

  1. Use this exception to wrap rate limit responses from external APIs or services.

  2. Always include the 'Retry-After' information when throwing this exception.

  3. Use descriptive error messages to distinguish between different rate limited services or endpoints.

  4. Handle other types of exceptions appropriately within the closure.

Error Messages

The error message for this exception should be descriptive and indicate which service or API triggered the rate limit. For example:

Rate limit exceeded by external API

Handling the Exception

Typically, you don't need to catch this exception yourself when using Guardian::send(). Guardian will handle it internally. However, if you're using the exception outside of Guardian, you can catch and handle it like this:

try {
    // Your code that might throw RateLimitExceededException
} catch (RateLimitExceededException $e) {
    $retryAfter = $e->getRetryAfter();
    $now = new DateTimeImmutable();
    $waitTime = $retryAfter->getTimestamp() - $now->getTimestamp();
    echo "Rate limit exceeded. Please try again in {$waitTime} seconds.";
}

Automatic Backoff Handling

When this exception is thrown inside a Guardian send() method:

  1. Guardian will catch the exception and record the rate limit violation.

  2. Subsequent calls to Guardian::send() for the same identifier will be automatically prevented until the rate limit resets.

  3. You don't need to implement additional retry or backoff logic; Guardian handles this for you.

Security Considerations

By properly using this exception to signal rate limit violations from external services, you ensure that your application respects both internal and external rate limits. This prevents accidental abuse of services and helps maintain good relationships with API providers.

Remember, the key to effective use of RateLimitExceededException is throwing it at the appropriate times within Guardian-protected closures, allowing Guardian to manage overall rate limiting behavior for your application.

Last updated