Skip to content

Commit 2dd5862

Browse files
committed
Add throttling for Django REST Framework
We add two limits to the number of requests from authenticated users and non-authenticated users to prevent the APIs from being overloaded.
1 parent 4d641c1 commit 2dd5862

File tree

2 files changed

+39
-0
lines changed

2 files changed

+39
-0
lines changed

promgen/settings.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,18 @@
199199
"DEFAULT_FILTER_BACKENDS": ("django_filters.rest_framework.DjangoFilterBackend",),
200200
"DEFAULT_SCHEMA_CLASS": "promgen.schemas.CustomSchema",
201201
"EXCEPTION_HANDLER": "promgen.middleware.custom_exception_handler",
202+
"DEFAULT_THROTTLE_CLASSES": [
203+
"rest_framework.throttling.AnonRateThrottle",
204+
"rest_framework.throttling.UserRateThrottle",
205+
],
206+
"DEFAULT_THROTTLE_RATES": {
207+
# Limits the rate of API calls that may be made by a given user.
208+
# The user id will be used as a unique cache key.
209+
"user": "1000/day",
210+
# Limits the rate of API calls that may be made by a anonymous users.
211+
# The IP address of the request will be used as the unique cache key.
212+
"anon": "100/day"
213+
},
202214
}
203215

204216
# If CELERY_BROKER_URL is set in our environment, then we configure celery as

promgen/tests/test_rest.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Copyright (c) 2018 LINE Corporation
22
# These sources are released under the terms of the MIT license: see LICENSE
3+
import django.core.cache
34
from django.contrib.auth.models import User, Permission
45
from django.test import override_settings
56
from django.urls import reverse
@@ -9,6 +10,11 @@
910

1011

1112
class RestAPITest(tests.PromgenTest):
13+
def setUp(self):
14+
super().setUp()
15+
# Clear the cache before each test to reset throttling
16+
django.core.cache.cache.clear()
17+
1218
@override_settings(PROMGEN=tests.SETTINGS)
1319
@override_settings(CELERY_TASK_ALWAYS_EAGER=True)
1420
def test_alert_blackhole(self):
@@ -1787,3 +1793,24 @@ def test_rest_shard(self):
17871793
response = self.client.get(reverse("api-v2:shard-projects", args=[1]))
17881794
self.assertEqual(response.status_code, 200)
17891795
self.assertEqual(response.json(), expected)
1796+
1797+
@override_settings(PROMGEN=tests.SETTINGS)
1798+
def test_throttling(self):
1799+
# Check throttling for anonymous users
1800+
for _ in range(100):
1801+
response = self.client.get(reverse("api-v2:service-list"))
1802+
self.assertEqual(response.status_code, 200)
1803+
response = self.client.get(reverse("api-v2:service-list"))
1804+
self.assertEqual(response.status_code, 429)
1805+
1806+
# Check throttling for authenticated users
1807+
token = Token.objects.filter(user__username="demo").first().key
1808+
for _ in range(1000):
1809+
response = self.client.get(
1810+
reverse("api-v2:service-list"), HTTP_AUTHORIZATION=f"Token {token}"
1811+
)
1812+
self.assertEqual(response.status_code, 200)
1813+
response = self.client.get(
1814+
reverse("api-v2:service-list"), HTTP_AUTHORIZATION=f"Token {token}"
1815+
)
1816+
self.assertEqual(response.status_code, 429)

0 commit comments

Comments
 (0)