Have you ever passed through an overbridge and noticed the sign stating the bridge weight restriction? Those restrictions are put in place to ensure public safety. Django REST Framework uses a similar process named throttling that controls the rate of requests that the client can make to an API. This rate limit restriction can ensure scalability, protection against slow performance and denial-of-service (DoS) attacks, and improve overall user experience.
The Django REST Framework has three throttling classes in the rest_framework.throttling module — AnonRate, UserRate, and ScopedRate throttle. All these classes specify throttling rules that signify the maximum number of requests in a given time within the scope. These classes have different mechanisms to specify the scope – to compare previous information with the new request. Let’s dig deep into the DRF throttling feature.
- AnonRateThrottle
- UserRateThrottle
- ScopedRateThrottle
Note: Please refer to Adding Permission in API – Django REST Framework and Customizing Object Level Permissions – Django REST Framework to make use of permission with throttling
AnonRateThrottle
AnonRateThrottle will throttle unauthenticated users. Using the IP address of the incoming request, a unique key is generated to throttle against. The allowed request rate is determined from any of the following:
- The rate property on the class – provided by overriding AnonRateThrottle and setting the property.
- The DEFAULT_THROTTLE_RATES[‘anon’] setting.
Let’s set the throttling policy globally. You can open the settings.py file and mention the throttle class and throttle rate as below:
Python3
REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES' 🙁 'rest_framework.authentication.BasicAuthentication' , ) 'DEFAULT_THROTTLE_CLASSES' : [ 'rest_framework.throttling.AnonRateThrottle' , ], 'DEFAULT_THROTTLE_RATES' : { 'anon' : '2/day' } } |
You can include second, minute, hour, or day as the throttle period (THROTTLE RATES).
Let’s try the HTTPie command to retrieve the robots. Here, we retrieve the list without providing any credentials.
http GET :8000/robot/
Output
HTTP/1.1 200 OK Allow: GET, POST, HEAD, OPTIONS Content-Language: en Content-Length: 2106 Content-Type: application/json Date: Sat, 02 Oct 2021 14:29:40 GMT Referrer-Policy: same-origin Server: WSGIServer/0.2 CPython/3.7.5 Vary: Accept, Accept-Language X-Content-Type-Options: nosniff X-Frame-Options: DENY [ { "currency": "USD", "currency_name": "US Dollar", "manufacturer": "ABB", "manufacturing_date": "2020-05-10T00:00:00Z", "name": "IRB 1100", "owner": "sonu", "price": 25000, "robot_category": "Articulated Robots", "url": "http://localhost:8000/robot/7/" }, { "currency": "USD", "currency_name": "US Dollar", "manufacturer": "ABB", "manufacturing_date": "2020-08-10T00:00:00Z", "name": "IRB 120", "owner": "sonu", "price": 35000, "robot_category": "Articulated Robots", "url": "http://localhost:8000/robot/8/" }, ]
Here, the anon throttle rate is set as 2 API requests per day. So, it doesn’t allow more than two requests. You will get below output if your request rate exceeds 2 requests.
UserRateThrottle
UserRateThrottle controls the rate of requests send by both authenticated and unauthenticated users. The user id is the unique cache key for authenticated requests, and the IP address is the unique cache key for unauthenticated requests.
The allowed request rate is determined from any of the following:
- The rate property on the class – provided by overriding UserRateThrottle and setting the property.
- The DEFAULT_THROTTLE_RATES[‘user’] setting.
You can edit the REST_FRAMEWORK dictionary as follows:
Python3
REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES' 🙁 'rest_framework.authentication.BasicAuthentication' , ) 'DEFAULT_THROTTLE_CLASSES' : [ 'rest_framework.throttling.AnonRateThrottle' , 'rest_framework.throttling.UserRateThrottle' ], 'DEFAULT_THROTTLE_RATES' : { 'anon' : '2/day' , 'user' : '5/day' } } |
The throttling rules in our REST_FRAMEWORK dictionary are as below:
- A maximum of 2 requests per day for unauthenticated users
- A maximum of 5 requests per day for authenticated users
The below authenticated HTTPie command allows 5 requests per day.
http -a “sonu”:”sn@pswrd” GET :8000/robot/
The restful web service raises too many requests for more than 5 requests per day.
ScopedRateThrottle
The ScopedRateThrottle class controls the rate of requests for specific features in our RESTFul web service. Here the view that is being accessed should include the .throttle_scope property. Let’s add a throttle scope to our RobotDetail class and mention the throttle rate for the scope.
First, let’s import the ScopedRateThrottle.
from rest_framework.throttling import ScopedRateThrottle
Now add the below lines of code
throttle_scope = 'robots' throttle_classes = (ScopedRateThrottle,)
Our RobotDetail class looks as follows:
Python3
class RobotDetail(generics.RetrieveUpdateDestroyAPIView): throttle_scope = 'robots' throttle_classes = (ScopedRateThrottle,) permission_classes = ( permissions.IsAuthenticatedOrReadOnly, custompermission.IsCurrentUserOwnerOrReadOnly, ) queryset = Robot.objects. all () serializer_class = RobotSerializer name = 'robot-detail' |
Next, let’s add the throttle rate for the scope ‘robots’.
Python3
REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES' 🙁 'rest_framework.authentication.BasicAuthentication' , ) 'DEFAULT_THROTTLE_CLASSES' : [ 'rest_framework.throttling.AnonRateThrottle' , 'rest_framework.throttling.UserRateThrottle' ], 'DEFAULT_THROTTLE_RATES' : { 'anon' : '2/day' , 'user' : '5/day' , 'robots' : '3/day' } } |
Let’s try the authenticated HTTPie request to retrieve the robot based on the id, which makes use of RobotDetail class to fetch the robot based on the id. The command is as follows:
http -a “sonu”:”sn@pswrd” GET :8000/robot/2/
Output
Here, our scope rate is 3 requests per day. We will get too many requests if it exceeds 3 requests. The output for the 4th request is as follows: