-
-
Notifications
You must be signed in to change notification settings - Fork 431
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1208 from vitalik/throttling
Throttling
- Loading branch information
Showing
10 changed files
with
752 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
# 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](https://www.django-rest-framework.org/api-guide/throttling/). 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 | ||
|
||
```Python | ||
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 | ||
|
||
```Python | ||
api = NinjaAPI() | ||
... | ||
|
||
api.add_router('/sensitive', 'myapp.api.router', throttle=AnonRateThrottle('100/m')) | ||
``` | ||
|
||
or directly to init of the Router class: | ||
|
||
```Python | ||
router = Router(..., throttle=[AnonRateThrottle('1000/h')]) | ||
``` | ||
|
||
|
||
### Operation level | ||
|
||
If `throttle` argument is passed to operation - it will overrule all global and router throttles: | ||
|
||
```Python | ||
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](guides/authentication.md) 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 | ||
|
||
```Python | ||
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) | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.