Hi everyone!
Here is a small article on some experiments I came across with the development of the new cfptime.org version. Goal: I needed to limit (anonymous) visitors on specific API endpoints (especially when creating/posting new Call For Papers to avoid flooding).
It turns out someone had similar thoughts and his blog post was pretty interested and helped me a lot. You can find the blog post here: https://www.pedaldrivenprogramming.com/2017/05/throttling-django-rest-framwork-viewsets/.
As the author states:
The magic is contained within the ScopedRateThrottle. This class will look for the
throttle_scope
property on the view, and if found, look up a corresponding key in theDEFAULT_THROTTLE_RATES
dictionary.
First, define your different throttles policies:
settings.py
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.AllowAny',),
'DEFAULT_THROTTLE_CLASSES': [
'rest_framework.throttling.AnonRateThrottle',
'rest_framework.throttling.ScopedRateThrottle'
],
'DEFAULT_THROTTLE_RATES': {
'anon': '100/min',
'user': '1000/day',
'cfps.create': '2/day'
}
}
Then, override the get_throttles()
method and add your cfps.create
policy when the action create
is called!
This will allow my users to use the CFP Time API to fetch {CFP, Conference} Details but will limit them in order to avoid flooding. w00t w00t!
views.py
class CFPViewSet(viewsets.ModelViewSet):
today = datetime.datetime.today()
queryset = Conference.objects.filter(reviewed=True, cfp_deadline__gte=today).order_by('cfp_deadline').values()
serializer_class = ConferenceSerializer
http_method_names = ['get', 'post']
def get_throttles(self):
if self.action == 'create':
self.throttle_scope = 'cfps.create'
return super().get_throttles()
@csrf_exempt
def create(self, request):
return super().create(request)
And after the second attempt…
curl -X POST "http://127.0.0.1:8000/api/cfps/" [... truncated ...] -D -
HTTP/1.1 429 Too Many Requests
Date: Tue, 14 Jan 2020 20:23:57 GMT
Server: WSGIServer/0.2 CPython/3.7.5
Content-Type: application/json
Retry-After: 86369
Vary: Accept, Cookie, Origin
Allow: GET, POST
X-Frame-Options: SAMEORIGIN
Content-Length: 72
{"detail":"Request was throttled. Expected available in 86369 seconds."}