Search code examples
djangodjango-rest-frameworktwilio-apithrottling

How to allow throttle only if the response was successful?


I'm trying to make throttling on OTP authentication so user can only send one message every minute

class BurstRateThrottle(AnonRateThrottle, UserRateThrottle):
    scope = 'burst'
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES':
    ('rest_framework_simplejwt.authentication.JWTAuthentication',),
    'DEFAULT_THROTTLE_CLASSES': [
        'rest_framework.throttling.AnonRateThrottle',
        'rest_framework.throttling.UserRateThrottle'
    ],
    'DEFAULT_THROTTLE_RATES': {
        'burst': '1/min',
        'anon': '200/min',
        'user': '250/min',
    },
@api_view(['POST'])
@permission_classes([AllowAny])
@throttle_classes([BurstRateThrottle])
def login_send_token(request):
    ...

The problem with this is that the api gets throttled even when the phone number is wrong so I'm trying to only throttle when the OTP message is send or when the response is 200 or 201

Is there any way to access the response status code in allow_request method? or to manually execute the throttle from the function that call twilio api?


Solution

  • I solved this by converting login_send_token to a class based view

    class LoginSendToken(APIView):
        permission_classes = [AllowAny]
        throttle_classes = [BurstRateThrottle]
    

    after that I overrode initial method and commented out the self.check_throttles(request) calling

        def initial(self, request, *args, **kwargs):
            """
            Runs anything that needs to occur prior to calling the method handler.
            """
            self.format_kwarg = self.get_format_suffix(**kwargs)
    
            # Perform content negotiation and store the accepted info on the request
            neg = self.perform_content_negotiation(request)
            request.accepted_renderer, request.accepted_media_type = neg
    
            # Determine the API version, if versioning is in use.
            version, scheme = self.determine_version(request, *args, **kwargs)
            request.version, request.versioning_scheme = version, scheme
    
            # Ensure that the incoming request is permitted
            self.perform_authentication(request)
            self.check_permissions(request)
            # self.check_throttles(request)
    

    and called check_throttles from my post method after serializer validation now it only checks throttling if the serializer was valid