Skip to content

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)