Protect Your API
Rate limiting prevents abuse and ensures fair usage.
Basic Laravel Rate Limiting
// routes/api.php
Route::middleware('throttle:60,1')->group(function () {
// 60 requests per minute
Route::get('/users', [UserController::class, 'index']);
});
Custom Rate Limiters
// AppServiceProvider
RateLimiter::for('api', function (Request $request) {
return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip());
});
// Different limits by plan
RateLimiter::for('api', function (Request $request) {
$user = $request->user();
return match($user?->plan) {
'premium' => Limit::perMinute(1000),
'basic' => Limit::perMinute(100),
default => Limit::perMinute(10)->by($request->ip()),
};
});
Return Rate Limit Headers
// Middleware adds these automatically
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1705312800
Handle 429 Responses
async function fetchWithRetry(url, retries = 3) {
const response = await fetch(url);
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After') || 60;
await sleep(retryAfter * 1000);
return fetchWithRetry(url, retries - 1);
}
return response;
}
Algorithms
Token Bucket: Smooth rate, allows bursts Sliding Window: More accurate, slightly more complex Fixed Window: Simple, but allows bursts at window edges
What to Limit
- Authentication endpoints (prevent brute force)
- Expensive operations (reports, exports)
- Write operations (create, update)
- Search/list endpoints
Be Generous, Then Tighten
Start with higher limits. Lower them if abuse occurs. Breaking existing integrations is painful.
