Let's talk about a feature called Rate Limiting, or in other words, called Throttling. What happens if the API is called too many times per minute or hour? Then the user receives an error with the message Too Many Attempts.
and 429 Too Many Requests HTTP status.
First, we must enable the API throttling for the Middleware.
bootstrap/app.php:
return Application::configure(basePath: dirname(__DIR__)) ->withProviders() ->withRouting( web: __DIR__.'/../routes/web.php', api: __DIR__.'/../routes/api.php', commands: __DIR__.'/../routes/console.php', health: '/up', apiPrefix: 'api/v1', ) ->withMiddleware(function (Middleware $middleware) { $middleware ->statefulApi() ->withThrottledApi(); }) ->withExceptions(function (Exceptions $exceptions) { // })->create();
Next, we can configure the rate limiter in the AppServiceProvider
boot
method. For example, we can limit the whole API to six requests per minute.
app/Providers/AppServiceProvider.php:
use Illuminate\Http\Request;use Illuminate\Cache\RateLimiting\Limit;use Illuminate\Support\Facades\RateLimiter; class AppServiceProvider extends ServiceProvider{ // ... public function boot(): void { RateLimiter::for('api', function (Request $request) { return Limit::perMinute(6)->by($request->user()?->id ?: $request->ip()); }); }}
If you need to set different rate limiters on some routes, this can be done using the throttle
Middleware and providing how many times per minute.
routes/api.php:
Route::get('/user', function (Request $request) { return $request->user();})->middleware('auth:sanctum'); Route::apiResource('categories', \App\Http\Controllers\Api\CategoryController::class) ->middleware('auth:sanctum'); Route::get('products', [\App\Http\Controllers\Api\ProductController::class, 'index']) ->middleware('throttle:2,1');
In this example, the product Route has a rate limiter for two requests every minute.
Sometimes, you need more logic for rate limiting. For example, a user with the role of admin can have unlimited requests, and a regular user has limited. For such cases, you will name the rate limiter and call it by name within the throttle
Middleware.
app/Providers/AppServiceProvider.php:
use Illuminate\Http\Request;use Illuminate\Support\ServiceProvider;use Illuminate\Cache\RateLimiting\Limit;use Illuminate\Support\Facades\RateLimiter; class AppServiceProvider extends ServiceProvider{ // ... public function boot(): void { RateLimiter::for('products', function (Request $request) { return $request->user()?->role === 'admin' ? Limit::none() : Limit::perMinute(5)->by($request->user()?->id ?: $request->ip()); }); }}
In the Route, we would call the products
limiter.
route/api.php:
Route::get('/user', function (Request $request) { return $request->user();})->middleware('auth:sanctum'); Route::apiResource('categories', \App\Http\Controllers\Api\CategoryController::class) ->middleware('auth:sanctum'); Route::get('products', [\App\Http\Controllers\Api\ProductController::class, 'index']) ->middleware('throttle:products');
To use throttling in such a way, first, you must remove the withThrottledApi
method from the Middleware in bootstrap/app.php
.