Skip to content

Intro

Standard Practice

  • Login Endpoint: Apply a stricter throttle, such as allowing only a limited number of attempts per minute or hour (e.g., 5 attempts per minute).

  • Signup Endpoint: You can also apply throttling here, but you might choose a more lenient rate depending on your user base and anticipated traffic (e.g., 10 signups per minute).

In your settings.py, you might set it up like this:

REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES': [
        'rest_framework.throttling.AnonRateThrottle',  # For anonymous users
        'rest_framework.throttling.UserRateThrottle',  # For authenticated users
    ],
    'DEFAULT_THROTTLE_RATES': {
        'anon': '5/minute',  # For login attempts
        'user': '1000/day',  # For general authenticated user actions
    },
}

Implementing throttling on public endpoints like login and signup is essential for securing your application against common attacks while maintaining a good user experience.


Built-in throlling vs django-ratelimit package

Both django-ratelimit and Django's built-in throttling (using Django Rest Framework's throttling) are used to control the rate at which requests are processed. However, they have different approaches and use cases. Here’s a breakdown of the core differences:

  • Functionality: It allows you to apply rate limiting on specific views by decorating them. You can specify limits based on various criteria (e.g., IP address, user, etc.).
  • Granularity: Offers more fine-grained control over rate limits for individual views.
  • Configuration: Requires decorators to be applied to each view you want to limit.
  • Flexibility: You can set different limits for different views easily.
  • Built-in Support: Throttling is integrated into DRF and can be configured globally or on a per-view basis using class-based views.
  • Rate Limiters: It provides several built-in classes like AnonRateThrottle and UserRateThrottle, which can be customized for different user types.
  • Settings-Based: Throttling limits can be defined in the settings, making it easy to manage across your application.
  • Middleware-like Behavior: Throttling operates at a middleware level, meaning it's applied automatically based on the defined rules.

Which One to Use?

Usedjango-ratelimit if you need:

  • More control over specific views or need to set different limits easily.
  • Custom logic or more complex rate limiting scenarios.

Use DRF Throttling if you prefer:

  • A straightforward and integrated approach to limit requests across the entire API.
  • A consistent and centralized configuration in your Django settings.

Conclusion

If you're building a DRF-based API, starting with DRF's built-in throttling might be the easier and more cohesive choice. For more complex or specific rate limiting needs, django-ratelimit offers additional flexibility.


Configuration

In your settings.py, configure the throttling classes. You can set global throttling rules here:

REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES': [
        'rest_framework.throttling.AnonRateThrottle',  # For anonymous users
        'rest_framework.throttling.UserRateThrottle',  # For authenticated users
    ],
    'DEFAULT_THROTTLE_RATES': {
        'anon': '100/day',  # 100 requests per day for anonymous users
        'user': '1000/day',  # 1000 requests per day for authenticated users
    },
}

You can apply throttling to specific views or viewsets using the throttle_classes attribute. Here's an example:

from rest_framework import viewsets
from rest_framework.permissions import IsAuthenticated
from rest_framework.throttling import UserRateThrottle, AnonRateThrottle
from .models import YourModel
from .serializers import YourModelSerializer

class YourModelViewSet(viewsets.ModelViewSet):
    queryset = YourModel.objects.all()
    serializer_class = YourModelSerializer
    permission_classes = [IsAuthenticated]
    throttle_classes = [UserRateThrottle]  # Apply user throttling to this view

# For a different view with different throttling
class AnotherViewSet(viewsets.ModelViewSet):
    queryset = YourModel.objects.all()
    serializer_class = YourModelSerializer
    throttle_classes = [AnonRateThrottle]  # Apply anonymous throttling to this view

If you need custom throttling logic, you can create a custom throttle class. Here's an example:

from rest_framework.throttling import SimpleRateThrottle

class CustomRateThrottle(SimpleRateThrottle):
    scope = 'custom_user'

    def get_cache_key(self, request, view):
        return request.user.username if request.user.is_authenticated else None

# Then, add your custom throttle class to settings.py
REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES': [
        'path.to.CustomRateThrottle',
    ],
    'DEFAULT_THROTTLE_RATES': {
        'custom_user': '10/minute',  # Example: 10 requests per minute
    },
}