Let’s create a real-world Laravel API that implements rate limiting. We’ll set up an API that retrieves posts while enforcing different rate limits based on user authentication.
Step 1: Create a Laravel API Route with Rate Limiting
Open routes/api.php
and define a route for fetching posts with different rate limits.
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\PostController;
Route::middleware(['auth:sanctum', 'throttle:20,1'])->get('/posts', [PostController::class, 'index']);
throttle:20,1
→ Allows 20 requests per minute for authenticated users.- If a user exceeds the limit, they receive a 429 Too Many Requests response.
Step 2: Implement Rate Limiting Based on User Role
Modify app/Providers/RouteServiceProvider.php
to apply different limits for admins and regular users.
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;
public function boot()
{
RateLimiter::for('api', function (Request $request) {
return $request->user()?->isAdmin()
? Limit::perMinute(100) // Admins: 100 requests per minute
: Limit::perMinute(20); // Regular users: 20 requests per minute
});
}
- Admins can make 100 requests per minute.
- Regular users are limited to 20 requests per minute.
Step 3: Create the PostController
Generate a controller to handle the API request:
php artisan make:controller PostController
Now, open app/Http/Controllers/PostController.php
and implement the index
method:
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Post;
class PostController extends Controller
{
public function index()
{
return response()->json([
'posts' => Post::latest()->take(10)->get(),
'message' => 'Retrieved posts successfully',
]);
}
}
Step 4: Customize the Rate Limit Exceeded Response
When a user exceeds the request limit, Laravel throws a ThrottleRequestsException
. You can customize the error message in app/Exceptions/Handler.php
:
use Illuminate\Http\Exceptions\ThrottleRequestsException;
public function render($request, Throwable $exception)
{
if ($exception instanceof ThrottleRequestsException) {
return response()->json([
'error' => 'Too many requests. Please slow down!',
'retry_after' => $exception->getHeaders()['Retry-After'] ?? 60,
], 429);
}
return parent::render($request, $exception);
}
- This customizes the 429 response with a user-friendly message.
- It also provides the
Retry-After
header so users know when they can try again.
Step 5: Test the API Rate Limiting
A) Using Postman or CURL
Try sending multiple requests to the /api/posts
endpoint:
curl -X GET http://your-app.test/api/posts
- If you send less than 20 requests per minute, you get posts as expected.
- If you exceed 20 requests per minute, you get:
{
"error": "Too many requests. Please slow down!",
"retry_after": 60
}
B) Testing Rate Limits in Laravel
Create a test case to check rate limiting:
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\RateLimiter;
use Tests\TestCase;
class RateLimitTest extends TestCase
{
public function test_rate_limit_exceeded()
{
RateLimiter::clear('api'); // Reset rate limits for the test
for ($i = 0; $i < 21; $i++) {
$response = $this->getJson('/api/posts');
}
$response->assertStatus(429)
->assertJson([
'error' => 'Too many requests. Please slow down!'
]);
}
}
Run the test:
php artisan test --filter=RateLimitTest
- If the test passes, the rate limiting is working correctly.
Conclusion
This example demonstrates how to enforce rate limiting in Laravel APIs. We covered: ✔ Setting fixed limits for endpoints
✔ Applying dynamic rate limits based on user roles
✔ Customizing rate limit responses
✔ Testing rate limits in Laravel
Comments