Installation:
composer require noxlogic/ratelimit-bundle
Add to config/bundles.php:
return [
// ...
Noxlogic\RateLimitBundle\NoxlogicRateLimitBundle::class => ['all' => true],
];
Enable Annotation:
Ensure Doctrine annotations are enabled in config/packages/doctrine.yaml:
doctrine:
orm:
annotations:
listen_for_updates: true
First Use Case:
Apply @RateLimit to a controller action:
use Noxlogic\RateLimitBundle\Annotation\RateLimit;
class ApiController extends AbstractController
{
/**
* @RateLimit(limit=10, interval=60)
*/
public function sensitiveAction()
{
// Your logic here
}
}
This limits the action to 10 calls per minute per user (or cache key).
API Rate Limiting:
Use @RateLimit on API endpoints to prevent abuse:
/**
* @RateLimit(limit=60, interval=3600) // 60 calls/hour
*/
public function getData()
{
return $this->json(['data' => '...']);
}
Custom Key Generation: Override the default key generator (e.g., for IP-based limits):
# config/packages/noxlogic_ratelimit.yaml
noxlogic_ratelimit:
key_generator: App\Service\CustomRateLimitKeyGenerator
Implement Noxlogic\RateLimitBundle\KeyGenerator\KeyGeneratorInterface:
class CustomRateLimitKeyGenerator implements KeyGeneratorInterface
{
public function generateKey(Request $request): string
{
return $request->getClientIp();
}
}
Dynamic Limits: Use a service to fetch limits from a database or config:
/**
* @RateLimit(limit=service("app.rate_limit_service").getLimit())
*/
public function dynamicAction()
{
// ...
}
Middleware Integration: Combine with Symfony middleware for global limits:
// src/EventListener/RateLimitListener.php
public function onKernelRequest(GetResponseEvent $event)
{
$request = $event->getRequest();
if ($request->attributes->has('_rate_limit')) {
$limit = $request->attributes->get('_rate_limit');
// Custom logic (e.g., return 429 if exceeded)
}
}
noxlogic_ratelimit.yaml:
noxlogic_ratelimit:
cache_pool: cache.app
OAuthKeyGenerator.RateLimitBundle's test utilities:
$this->container->get('noxlogic_ratelimit.cache')->clear();
Annotation Parsing:
kernel.request event if needed.attributes in config/packages/framework.yaml for attribute-based alternatives:
framework:
attributes:
enabled: true
Cache Key Collisions:
user_id (from FOSOAuth) or ip. For shared limits (e.g., team accounts), customize the key generator to include additional context (e.g., user_id + team_id).Performance:
cache:clear operations.Configuration Overrides:
noxlogic_ratelimit.yaml must match the bundle’s expected structure. Validate with:
php bin/console debug:config noxlogic_ratelimit
php bin/console debug:container --tag="noxlogic_ratelimit.key_generator"
RateLimitListener to log 429 responses:
public function onKernelException(GetResponseForExceptionEvent $event)
{
if ($event->getException() instanceof RateLimitExceededException) {
$this->logger->warning('Rate limit exceeded', [
'action' => $event->getRequest()->get('_route'),
'key' => $event->getRequest()->attributes->get('_rate_limit_key'),
]);
}
}
Custom Exceptions:
Override the default RateLimitExceededException:
class CustomRateLimitException extends \Exception implements RateLimitExceededExceptionInterface
{
public function getRetryAfter(): int
{
return $this->retryAfter;
}
}
Register in services.yaml:
Noxlogic\RateLimitBundle\EventListener\RateLimitListener:
arguments:
$exceptionClass: App\Exception\CustomRateLimitException
Async Validation:
Use Symfony’s EventDispatcher to validate limits asynchronously (e.g., in a queue):
$eventDispatcher->dispatch(new RateLimitCheckEvent($request, $limit));
Rate Limit Headers:
Add X-RateLimit-* headers manually in a subscriber:
public function onKernelResponse(FilterResponseEvent $event)
{
$response = $event->getResponse();
$remaining = $this->cache->get($key . ':remaining');
$response->headers->set('X-RateLimit-Remaining', $remaining);
}
Bulk Actions: For batch operations (e.g., bulk API calls), use a shared key or increment the limit dynamically:
/**
* @RateLimit(limit=service("app.bulk_rate_limit_service").getBulkLimit())
*/
public function bulkAction()
{
// ...
}
How can I help you explore Laravel packages today?