DEV Community

Mehedi Hasan
Mehedi Hasan

Posted on

How to Create API Rate Limit Policies in Laravel

In modern API development, managing the rate of incoming requests is crucial for maintaining performance, preventing abuse, and ensuring the smooth operation of your application. Laravel provides an out-of-the-box solution for implementing API rate limiting, allowing developers to easily create rate limit policies to control how often an API can be accessed within a given timeframe. This guide will walk you through the steps for creating API rate limit policies in Laravel.


What is Rate Limiting?

Rate limiting refers to the process of controlling the number of requests a user, application, or service can make to an API within a defined period. This helps to:

  • Protect against Denial of Service (DoS) attacks by limiting excessive requests from a single source.
  • Prevent server overload and maintain application performance.
  • Ensure fair usage of APIs, especially when serving multiple users or applications.

Laravel’s built-in rate limiting is based on IP addresses, and it can be easily customized to meet the specific needs of your API.


Step 1: Basic Rate Limiting in Laravel

Laravel's rate limiting feature is primarily handled by the ThrottleRequests middleware. By default, Laravel applies a global rate limit to all API routes using this middleware.

The rate limit is defined in the api middleware group in app/Http/Kernel.php:

'api' => [
    \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
    'throttle:api',
    \Illuminate\Routing\Middleware\SubstituteBindings::class,
],
Enter fullscreen mode Exit fullscreen mode

Here, the throttle:api middleware is responsible for limiting API requests. Laravel uses 60 requests per minute as the default rate limit.


Step 2: Customizing Rate Limits for APIs

To define custom rate limit policies, you can modify the configureRateLimiting method within the app/Providers/RouteServiceProvider.php file.

Here’s how to customize the rate limit:

use Illuminate\Support\Facades\RateLimiter;

protected function configureRateLimiting()
{
    RateLimiter::for('api', function ($request) {
        return $request->user()
                    ? Limit::perMinute(100)->by($request->user()->id)  // Authenticated users
                    : Limit::perMinute(60)->by($request->ip());  // Guests based on IP address
    });
}
Enter fullscreen mode Exit fullscreen mode

In this example:

  • Authenticated users can make up to 100 requests per minute.
  • Guest users (or users not authenticated) can make up to 60 requests per minute, based on their IP address.

The by() method is used to specify the key used to track the rate limits. For authenticated users, it’s based on their user ID, while for guests, it's based on their IP address.


Step 3: Creating Different Rate Limiters for Specific Routes

You can create custom rate limiters for specific API routes or groups of routes. For example, you may want to apply stricter rate limits to some high-traffic endpoints or more lenient limits for trusted users.

Let’s create different rate limits for POST requests to the login route and for the default GET requests to general API routes.

In RouteServiceProvider.php, define your custom limiters:

protected function configureRateLimiting()
{
    RateLimiter::for('global', function ($request) {
        return Limit::perMinute(60);  // Global rate limit
    });

    RateLimiter::for('login', function ($request) {
        return Limit::perMinute(10)->by($request->ip());  // Strict limit for login attempts
    });

    RateLimiter::for('trusted-user', function ($request) {
        return $request->user()->isTrusted()
            ? Limit::none()  // No rate limit for trusted users
            : Limit::perMinute(100)->by($request->user()->id);
    });
}
Enter fullscreen mode Exit fullscreen mode

Then, apply these rate limits to the routes in your routes/api.php file:

use Illuminate\Support\Facades\Route;

Route::middleware('throttle:login')->post('/login', 'AuthController@login');
Route::middleware('throttle:global')->get('/posts', 'PostController@index');
Route::middleware('throttle:trusted-user')->get('/special-data', 'SpecialDataController@index');
Enter fullscreen mode Exit fullscreen mode

In this example:

  • The login route is limited to 10 requests per minute, preventing brute force login attempts.
  • The GET /posts route is limited to 60 requests per minute globally.
  • Trusted users can access the /special-data route without any rate limits.

Step 4: Customizing Rate Limiting with Dynamic Conditions

Laravel also allows dynamic rate limiting based on specific conditions, such as user roles, API key tiers, or request content.

For example, you can limit based on a user’s subscription plan or other criteria by extending the rate limiting logic:

RateLimiter::for('api', function ($request) {
    $user = $request->user();

    if ($user && $user->isPremium()) {
        // Premium users get higher limits
        return Limit::perMinute(500)->by($user->id);
    }

    return Limit::perMinute(100)->by(optional($user)->id ?: $request->ip());
});
Enter fullscreen mode Exit fullscreen mode

In this scenario:

  • Premium users can make up to 500 requests per minute.
  • Regular users can make up to 100 requests per minute.

This dynamic condition offers flexibility for rate limiting based on user behavior, roles, or any other attributes.


Step 5: Handling Rate Limiting Responses

When a user exceeds their rate limit, Laravel automatically returns a 429 Too Many Requests response with information about when they can retry the request. You can customize this response by modifying the ThrottleRequests middleware, but in most cases, the default behavior is sufficient.

For example, here’s what a typical response might look like:

{
    "message": "Too Many Attempts.",
    "retry_after": 60,
    "rate_limit_remaining": 0
}
Enter fullscreen mode Exit fullscreen mode

The retry_after header indicates how long the user must wait before making additional requests.


Step 6: Rate Limiting for Authenticated Users with Tokens (Sanctum/Passport)

When using Laravel Passport or Sanctum for API authentication, you can still apply rate limiting policies based on API tokens.

For example, with Laravel Sanctum, you can create rate limits based on the authenticated user:

RateLimiter::for('api', function ($request) {
    return Limit::perMinute(100)->by(optional($request->user())->id ?: $request->ip());
});
Enter fullscreen mode Exit fullscreen mode

This works well when you want to control API access on a per-user basis rather than by IP, ensuring that rate limits are applied fairly, regardless of network conditions or shared IP addresses.


Step 7: Testing and Monitoring Rate Limiting

After implementing rate limiting, it’s important to test how it performs under load and monitor its impact on your API. Some tools that can help you test rate limits include:

  • Postman: You can create collections and send multiple requests in a loop to see how your API handles limits.
  • Laravel Telescope: Laravel Telescope provides detailed monitoring of requests and can be used to log rate limiting events.
  • Logging: You can log rate limiting events to identify when users or clients are frequently hitting rate limits, which may indicate abuse or performance issues.

Conclusion

Rate limiting is an essential aspect of API management that ensures your Laravel application remains performant, secure, and fair for all users. Laravel's built-in rate limiter provides flexibility and ease of use, allowing you to define custom rate limiters based on various conditions like user roles, IP addresses, or subscription plans. By effectively configuring and applying rate limit policies, you can safeguard your API from abuse, prevent server overloads, and maintain a high-quality user experience.

Top comments (0)