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

Categorized in: