DRF Throttle Types

DRF throttle types

Throttling is a way of controlling the way your system resources are used. Throttling is generally set temporarily on the resources used by the end users. I will explain the throttle types that exist in the Django Rest Framework (aka DRF).

As it can be set on API views to limit end users from greedily consuming your resources, it is another way to neutralize the security vulnerabilities in your website.

For example, you have a website with login and register pages. If you don’t set any throttling in your login pages, someone can easily establish brute-force attacks on the users in your system. Eventually, they will both consume your resources, they can crash your website and make it unavailable for days, and can crack passwords at a glance. I don’t even want to mention the case that you have an OTP verification on your registration page.

Considering those nightmares, the saviour of your day will be the rate throttling. It’ll save you electricity, money, time, etc.

There are 3 default throttle types in Django Rest Framework:

  • AnonRateThrottle: Only applies to unauthorized users, generates cache key by using their IPs.
  • UserRateThrottle: Applies to both authorized and unauthorized users, generates cache key by using their user pk for authorized and IP address for unauthorized users.
  • ScopedRateThrottle:  Applies to the views you selected, with the rates you specified.

AnonRateThrottle

In your settings.py specify the AnonRateThrottle and its rate inside DEFAULT_THROTTLE_RATES:

REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES': [
        'rest_framework.throttling.AnonRateThrottle',
    ],
    'DEFAULT_THROTTLE_RATES': {'anon': '250/day'}
}

You can specify your rates with one of secondminutehour or day. Then in your view, you can start using it just by defining the throttle_classes as a view attribute.

from rest_framework.throttling import AnonRateThrottle
from rest_framework import viewsets
from app.serializers import ItemSerializer


class ItemsViewSet(viewsets.ModelViewSet):
    queryset = Item.objects.all()
    serializer_class = ItemSerializer
    throttle_classes = [AnonRateThrottle]
    http_method_names = ['get', 'post', 'delete']

UserRateThrottle

The use of this throttle type is the same as AnonRateThrottle.

REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES': [
        'rest_framework.throttling.AnonRateThrottle',
        'rest_framework.throttling.UserRateThrottle'
    ],
    'DEFAULT_THROTTLE_RATES': {'anon': '5/day', 'user': '100/day'}
}
from rest_framework.throttling import UserRateThrottle
from rest_framework import viewsets
from app.serializers import ItemSerializer


class ItemsViewSet(viewsets.ModelViewSet):
    queryset = Item.objects.all()
    serializer_class = ItemSerializer
    throttle_classes = [UserRateThrottle]
    http_method_names = ['post', 'put', 'delete']

ScopedRateThrottle

Here you need to specify the key and the rate inside DEFAULT_THROTTLE_RATES especially.

The key names all should be unique.

REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES': [
        'rest_framework.throttling.ScopedRateThrottle'
    ],
    'DEFAULT_THROTTLE_RATES': {
        'login': '10/min',
        'register': '10/min',
        'create_item': '5/min',
    }
}
from rest_framework.throttling import ScopedRateThrottle
from rest_framework.views import APIView


class CustomLoginView(APIView):
    throttle_classes = [ScopedRateThrottle]
    throttle_scope = "login"


class CustomLoginView(APIView):
    throttle_classes = [ScopedRateThrottle]
    throttle_scope = "register"

Custom Throttle Classes

By the way, you can extend any of the throttle classes mentioned above and create your own. You use a third-party service for OTP verification and want to prevent people from abusing it. It is possible for a user to enter the wrong OTP code each time, triggering repeated OTP code sendings, for the purpose of exploiting your money. In the case of a wrong OTP verification, users will get the status code 406 Not Acceptable, and you can simply handle this status code in your throttle class and save yourself the trouble.

Resources:
https://www.django-rest-framework.org/api-guide/throttling/