14
How to throttle your API with Django Rest Framework
Control the rate of requests that clients can make to your API.
As DRF says, throttling is
Throttling is similar to permissions, in that it determines if a request should be authorized. Throttles indicate a temporary state, and are used to control the rate of requests that clients can make to an API
In other words, we can say that throttling is a mechanism for limiting how many requests my API can accept in a period of time, we can specify this limit per user, IP address, etc. This is similar to how some APIs limit the number of requests you can make in a day or an hour.
As with permissions and authentication, throttling in DRF is always defined as a list of classes.
Before running the main body of the view each throttle in the list is checked. If any throttle check fails an exceptions.Throttled
exception will be raised, and the main body of the view will not run.
And the same as permissions we can set these throttles globally and per views.
We can set a global default throttling policy using the DEFAULT_THROTTLE_CLASSES
and DEFAULT_THROTTLE_RATES
settings.
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': [
'rest_framework.throttling.AnonRateThrottle',
'rest_framework.throttling.UserRateThrottle'
],
'DEFAULT_THROTTLE_RATES': {
'anon': '20/day',
'user': '50/day'
}
}
The rate descriptions used in DEFAULT_THROTTLE_RATES
may include second
, minute
, hour
, or day
as the throttle period.
With these settings,
Unauthenticated users will be able to only make 20 requests per day to our API, the IP address of the incoming request is used to generate a unique key to throttle against.
Authenticated users will be able to make 50 requests per day to our API, for these the id of the user is going to be used to generate the unique key.
When they reached the maximum of requests our API will respond with the error code 429 - Too Many Requests
Since this is the global configuration this will apply to all views, but we can still override these settings per view.
It's always better to have control over what views we want to limit, for this DRF offers us the possibility of setting these throttles classes per view.
We do this by passing a list of throttles classes to the throttle_classes
attribute on the APIView
class-based views.
from rest_framework.response import Response
from rest_framework.throttling import UserRateThrottle
from rest_framework.views import APIView
class ExampleView(APIView):
throttle_classes = [UserRateThrottle]
def get(self, request, format=None):
content = {
'status': 'request was permitted'
}
return Response(content)
In this way, ExampleView
will use the UserRateThrottle
class to limit the number of requests that this view can receive, the rates, in this case, are still defined on the DEFAULT_THROTTLE_CLASSES
settings key.
But what if we want to specify a different rate for a specific view, we can do this by extending the UserRateThrottle
class and specifying a new rate.
from rest_framework.response import Response
from rest_framework.throttling import UserRateThrottle
from rest_framework.views import APIView
class CustomUserRateThrottle(UserRateThrottle):
rate= '5/day'
class VeryLimitedView(APIView):
throttle_classes = [CustomUserRateThrottle]
def get(self, request, format=None):
content = {
'status': 'request was permitted'
}
return Response(content)
Now only for this view the authenticated users have 5 requests per day, even though the global settings say that the users have 50 requests per day.
The ScopedRateThrottle
class can be used to restrict access to specific parts of the API. This throttle will only be applied if the view that is being accessed includes a .throttle_scope
attribute.
The allowed request rate is determined by the DEFAULT_THROTTLE_RATES
setting using a key from the request "scope".
For example, given the following views...
class ContactListView(APIView):
throttle_scope = 'contacts'
...
class ContactDetailView(APIView):
throttle_scope = 'contacts'
...
class UploadView(APIView):
throttle_scope = 'uploads'
...
...and the following settings.
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': [
'rest_framework.throttling.ScopedRateThrottle',
],
'DEFAULT_THROTTLE_RATES': {
'contacts': '100/day',
'uploads': '50/day'
}
}
User requests to either ContactListView
or ContactDetailView
would be restricted to a total of 100 requests per day. User requests to UploadView
would be restricted to 50 requests per day.
As we saw, throttles is a powerful and really helpful feature that we can implement on our API if we need to impose different constraints on different parts of the API, due to some services being particularly resource-intensive. Also, it's worth mentioning that DRF provides a BaseThrottle
class which you can override to create custom throttles with custom implementations.
If you plan to use this method as a security feature just consider that the DRF throttling isn't intended as a security feature, it has some weaknesses and you shouldn't rely only upon the throttling.
Yet, it's a cool feature and you should definitely try it on your API.
14