Installation
composer require coka/rate-limit-bundle
Enable the bundle in config/bundles.php:
CedrickOka\RateLimitBundle\CedrickOkaRateLimitBundle::class => ['all' => true],
Basic Configuration
Add to config/packages/cedrick_oka_rate_limit.yaml:
cedrick_oka_rate_limit:
limits:
default: 100 # Requests per minute
storage: cache # Options: cache, redis, database
First Use Case Apply rate limiting to a controller method:
use CedrickOka\RateLimitBundle\Annotation\RateLimit;
class ApiController extends AbstractController
{
/**
* @RateLimit(limit=50, time=60)
*/
public function sensitiveEndpoint()
{
return new JsonResponse(['data' => '...']);
}
}
Annotation-Based Limiting
Use @RateLimit on controller methods or classes:
/**
* @RateLimit(limit=10, time=300, message="Too many requests")
*/
public function login()
{
// ...
}
Dynamic Limits via Middleware Override limits programmatically:
public function handle(Request $request, Closure $next)
{
$request->attributes->set('rate_limit', [
'limit' => 200, // Override
'time' => 3600,
]);
return $next($request);
}
Storage Backends
config/packages/cedrick_oka_rate_limit.yaml:storage: redis
redis:
dsn: "redis://localhost:6379"
Event-Based Extensions
Listen to rate_limit.exceeded events for custom responses:
public function onRateLimitExceeded(RateLimitExceededEvent $event)
{
$event->setResponse(new JsonResponse(['error' => 'Custom message'], 429));
}
Caching Quirks
default cache by default. Ensure cache:clear is run after config changes.namespace: "app_" in config.Annotation Parsing
@RateLimit annotations:
php bin/console cache:clear
Performance
time values (e.g., time=86400 for daily limits) in cache backends.CORS Headers
The bundle auto-adds X-RateLimit-* headers but does not handle CORS policies. Configure manually in config/packages/nelmio_cors.yaml if needed.
$limit = $request->attributes->get('rate_limit');
$this->logger->debug('Rate limit', ['limit' => $limit]);
redis-cli to inspect keys:
redis-cli KEYS "rate_limit:*"
rate_limit.exceeded event to log details:
$event->getRequest()->attributes->get('rate_limit');
Custom Storage
Implement CedrickOka\RateLimitBundle\Storage\StorageInterface:
class CustomStorage implements StorageInterface
{
public function increment($key, $limit, $time)
{
// Custom logic (e.g., database)
}
}
Register in config:
storage: custom
custom:
class: App\Storage\CustomStorage
Response Customization
Extend the RateLimitListener to modify responses:
public function onKernelException(GetResponseForExceptionEvent $event)
{
if ($event->getException() instanceof RateLimitExceededException) {
$event->setResponse(new Response('Custom 429', 429, [
'X-Custom-Header' => 'value',
]));
}
}
IP-Based vs. Token-Based
Override the getKey() method in a custom listener to use tokens (e.g., API keys) instead of IPs:
$key = $request->headers->get('X-API-KEY') ?: $request->getClientIp();
How can I help you explore Laravel packages today?