throttler
throttler copied to clipboard
Throttle on only a single route
Is there an existing issue that is already proposing this?
- [X] I have searched the existing issues
Is your feature request related to a problem? Please describe it
My challenge is how to apply throttling to a specific route without setting up a global throttle. My concern arises from the necessity to log every single request from every single user (in memory) when establishing a global throttling system, to ascertain whether the new request necessitates throttling. How can I accomplish this?
Describe the solution you'd like
Globally config it like:
imports: [
...
ThrottlerModule.forRoot()
]
and use it like this on the route:
@Throttle([{ limit: 3, ttl: 60000 }])
@Get()
findAll() {
return "List users works with custom rate limiting.";
}
Notes:
- It's better to remove the default keyword on the Throttle decorator
- It's good to add support for arrays inside the Throttle decorator
- I have tested the global config and added a guard with an empty config and it doesn't work.
Teachability, documentation, adoption, migration strategy
No response
What is the motivation / use case for changing the behavior?
For more customizations and more control for throttling and saving more space.
@canoir it was your company's concern too, right?
Okay, I think I see the request here. Instead of being forced to use the ThrottlerModule
it would be nice to set the @UseGuards()
and @Throttle()
on a case-by-case basis, correct?
I think the ThrottlerModule
should still be imported for the access to the storage service, but that may be movable to not be required in a dynamic module, or we just keep the forRoot
as is and allow an empty function call (easiest as there's no changes there)
In the @Throttle()
, I can probably allow it to take in the config or a record of name: config
for sake of ease and transform it under the hood. If we were to take in either the record or the array, if the array had two configurations, both without name, the latter would overwrite the former and lead to unexpected behavior. Do you think this would make for a good DX?
As for the initial "How can I implement this?", so long as there's a config object passed to the forRoot()
(something that has a ttl
and limit
, it can be ridiculous numbers too, e.g. [{ limit: 0, ttl: 0 }]
) the n the guard should work with the overwrite from the @Throttle()
decorator
Okay, I think I see the request here. Instead of being forced to use the
ThrottlerModule
it would be nice to set the@UseGuards()
and@Throttle()
on a case-by-case basis, correct?I think the
ThrottlerModule
should still be imported for the access to the storage service, but that may be movable to not be required in a dynamic module, or we just keep theforRoot
as is and allow an empty function call (easiest as there's no changes there)In the
@Throttle()
, I can probably allow it to take in the config or a record ofname: config
for sake of ease and transform it under the hood. If we were to take in either the record or the array, if the array had two configurations, both without name, the latter would overwrite the former and lead to unexpected behavior. Do you think this would make for a good DX?As for the initial "How can I implement this?", so long as there's a config object passed to the
forRoot()
(something that has attl
andlimit
, it can be ridiculous numbers too, e.g.[{ limit: 0, ttl: 0 }]
) the n the guard should work with the overwrite from the@Throttle()
decorator
I agree with you and about the name: config , I think that is great too, our need is exactly what you said, but your other answer make me a bigger question, what will happen if we pass ttl: 0 and limit 0 to global config? I mean if the guard only passes cause of 0 then there is a little bit shitty but solution to our problem even now, right?
The idea I suggested was just to make sure that there was a default config so that the @Throttle()
override properly works. So long as the guard is not applied to any routes without the @Throttle()
then the point is moot,. If it is, you'll find out pretty quickly :smile:
It took me an hour to realize that I need to have a default config block, even if I'm not using it. I'd say it should have a default if not specified.
So, I'm not sure if I'm just doing something wrong but:
- [x] Global throttling configuration with a global
ThrottlerGuard
provider works - [ ] Global throttling configuration + overriding controller method (ignored)
- [ ] Global throttling configuration + overriding controller method + providing
ThrottlerGuard
specifically for module (ignored)
How would I mark only certain routes to be throttled then?
@Throttle({ long: { limit: 5, ttl: 60000 } })
@dominic-schmid currently it would be like this:
- import throttler with a default configuration provided
- mark your route with the
@Throttle
line and a@UseGuards(ThrottlerGuard)
For all routes to be affected, there is another way to apply the ThrottlerGuard globally. Otherwise, it is only going to affect specific routes marked with the ThrottlerGuard.
This issue is concerning step 1 - it would be better if there was a preconfigured "default" rather than needing to specify a dummy configuration if you are using custom limit/ttl for each route.
Having same problem - I do use module with default configuration, however there are routes that I would like to use different rate limit that is defined in module. Currently I cannot do it without overriding default configurations... Any ideas how to workaround it?
Having same problem - I do use module with default configuration, however there are routes that I would like to use different rate limit that is defined in module. Currently I cannot do it without overriding default configurations... Any ideas how to workaround it?
@jvvcn that's kind of the idea of what should be done. Is there something you'd rather be able to do?