Laravel RateLimiter

Jjj picture Jjj · Jun 29, 2020 · Viewed 7.3k times · Source

I'm fairly new to Laravel and am currently using an API that has a limit of 25 requests per minute. I have a controller method sendRequest() which is used by all methods to send requests to the API so I was thinking this is the place to put a rate limiter that checks if the current request can be added to the queue if the limit is not yet reached.

I was thinking something like this:

protected function sendRequest(){
    if ($this->allowRequest()) {
        //proceed to api call
    }
}

protected function allowRequest() {
    $allow = false;
    //probably a do-while loop to check if the limit has been reached within the timeframe?
}

I've found this class Illuminate\Cache\RateLimiter that I think could be useful but have no idea how to use it yet. Can anyone point me to the right direct with this? So basically the request should "wait" and execute only if the 25 requests/minute limit hasn't been reached.

Thanks!

Answer

Hafez Divandari picture Hafez Divandari · Jun 29, 2020

The Illuminate\Cache\RateLimiter class has hit and tooManyAttempts methods you can use like this:

use Illuminate\Cache\RateLimiter;
use Illuminate\Http\Request;

protected function sendRequest()
{
    if ($this->hasTooManyRequests()) {
        // wait
        sleep(
            $this->limiter()
                ->availableIn($this->throttleKey()) + 1 // <= optional plus 1 sec to be on safe side
        );

        // Call this function again.
        return $this->sendRequest();
    }
    
    //proceed to api call
    $response = apiCall();

    // Increment the attempts
    $this->limiter()->hit(
        $this->throttleKey(), 60 // <= 60 seconds
    );

    return $response;
}

/**
 * Determine if we made too many requests.
 *
 * @return bool
 */
protected function hasTooManyRequests()
{
    return $this->limiter()->tooManyAttempts(
        $this->throttleKey(), 25 // <= max attempts per minute
    );
}

/**
 * Get the rate limiter instance.
 *
 * @return \Illuminate\Cache\RateLimiter
 */
protected function limiter()
{
    return app(RateLimiter::class);
}

/**
 * Get the throttle key for the given request.
 *
 * @return string
 */
protected function throttleKey()
{
    return 'custom_api_request';
}

See Illuminate\Cache\RateLimiter class for more available methods.

You may also check Illuminate\Foundation\Auth\ThrottlesLogins as an example to figure out how to use Illuminate\Cache\RateLimiter class.

Note: The RateLimiter methods use seconds instead of minutes since Laravel >= 5.8 and got a major improvement on v8.x.