Throttling
Throttles allows to control the rate of requests that clients can make to an API. Django Ninja allows to set custom throttlers globally (across all operations in NinjaAPI instance), on router level and each operation individually.
Note
The application-level throttling that Django Ninja provides should not be considered a security measure or protection against brute forcing or denial-of-service attacks. Deliberately malicious actors will always be able to spoof IP origins. The built-in throttling implementations are implemented using Django's cache framework, and use non-atomic operations to determine the request rate, which may sometimes result in some fuzziness.
Django Ninja’s throttling feature is pretty much based on what Django Rest Framework (DRF) uses, which you can check out here. So, if you’ve already got custom throttling set up for DRF, there’s a good chance it’ll work with Django Ninja right out of the box. They key difference is that you need to pass initialized Throttle objects instead of classes (which should give a better performance)
Usage
Global
The following example will limit unauthenticated users to only 10 requests per second, while authenticated can make 100/s
from ninja.throttling import AnonRateThrottle, AuthRateThrottle
api = NinjaAPI(
throttle=[
AnonRateThrottle('10/s'),
AuthRateThrottle('100/s'),
],
)
Tip
throttle
argument accepts single object and list of throttle objects
Router level
Pass throttle
argument either to add_router
function
api = NinjaAPI()
...
api.add_router('/sensitive', 'myapp.api.router', throttle=AnonRateThrottle('100/m'))
or directly to init of the Router class:
router = Router(..., throttle=[AnonRateThrottle('1000/h')])
Operation level
If throttle
argument is passed to operation - it will overrule all global and router throttles:
from ninja.throttling import UserRateThrottle
@api.get('/some', throttle=[UserRateThrottle('10000/d')])
def some(request):
...
Builtin throttlers
AnonRateThrottle
Will only throttle unauthenticated users. The IP address of the incoming request is used to generate a unique key to throttle against.
UserRateThrottle
Will throttle users (if you use django build-in user authentication) to a given rate of requests across the API. The user id is used to generate a unique key to throttle against. Unauthenticated requests will fall back to using the IP address of the incoming request to generate a unique key to throttle against.
AuthRateThrottle
Will throttle by Django ninja authentication to a given rate of requests across the API. Unauthenticated requests will fall back to using the IP address of the incoming request to generate a unique key to throttle against.
Note: the cache key in case of request.auth
will be generated by sha256(str(request.auth))
- so if you returning some custom objects inside authentication make sure to implement __str__
method that will return a unique value for the user.
Custom throttles
To create a custom throttle, override BaseThrottle
(or any of builtin throttles) and implement .allow_request(self, request)
. The method should return True
if the request should be allowed, and False
otherwise.
Example
from ninja.throttling import AnonRateThrottle
class NoReadsThrottle(AnonRateThrottle):
"""Do not throttle GET requests"""
def allow_request(self, request):
if request.method == "GET":
return True
return super().allow_request(request)