Skip to content

Commit

Permalink
[feature] Added throttling of API requests #34
Browse files Browse the repository at this point in the history
closes #34
  • Loading branch information
ManishShah120 committed Jan 12, 2021
1 parent b130a44 commit 043a06d
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 28 deletions.
13 changes: 13 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,19 @@ and in the `Browsable web page <#browsable-web-interface>`_ of each endpoint,
here we'll provide just a list of the available endpoints,
for further information please open the URL of the endpoint in your browser.

Throttling Policy
=================

For overriding the default throttling settings for the API endpoints, add this to the `settings.py` file. The rate descriptions used in `DEFAULT_THROTTLE_RATES` may include `second`, `minute`, `hour` or `day` as the throttle period.

.. code-block:: text
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_RATES': {
'ipam': '100/hour',
}
}
Get Next Available IP
=====================

Expand Down
42 changes: 15 additions & 27 deletions openwisp_ipam/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@
Subnet = swapper.load_model('openwisp_ipam', 'Subnet')


class ProtectedAPIMixin(object):
authentication_classes = [BearerAuthentication, SessionAuthentication]
permission_classes = [DjangoModelPermissions]
throttle_scope = 'ipam'


class ListViewPagination(pagination.PageNumberPagination):
page_size = 10
page_size_query_param = 'page_size'
Expand Down Expand Up @@ -137,57 +143,45 @@ def index_of(self, address):
return index


class AvailableIpView(RetrieveAPIView):
class AvailableIpView(ProtectedAPIMixin, RetrieveAPIView):
subnet_model = Subnet
queryset = IpAddress.objects.none()
authentication_classes = (BearerAuthentication, SessionAuthentication)
permission_classes = (DjangoModelPermissions,)

def get(self, request, *args, **kwargs):
subnet = get_object_or_404(self.subnet_model, pk=self.kwargs['subnet_id'])
return Response(subnet.get_next_available_ip())


class IpAddressListCreateView(ListCreateAPIView):
class IpAddressListCreateView(ProtectedAPIMixin, ListCreateAPIView):
subnet_model = Subnet
serializer_class = IpAddressSerializer
authentication_classes = (BearerAuthentication, SessionAuthentication)
permission_classes = (DjangoModelPermissions,)
pagination_class = ListViewPagination

def get_queryset(self):
subnet = get_object_or_404(self.subnet_model, pk=self.kwargs['subnet_id'])
return subnet.ipaddress_set.all().order_by('ip_address')


class SubnetListCreateView(ListCreateAPIView):
class SubnetListCreateView(ProtectedAPIMixin, ListCreateAPIView):
serializer_class = SubnetSerializer
authentication_classes = (BearerAuthentication, SessionAuthentication)
permission_classes = (DjangoModelPermissions,)
pagination_class = ListViewPagination
queryset = Subnet.objects.all()


class SubnetView(RetrieveUpdateDestroyAPIView):
class SubnetView(ProtectedAPIMixin, RetrieveUpdateDestroyAPIView):
serializer_class = SubnetSerializer
authentication_classes = (BearerAuthentication, SessionAuthentication)
permission_classes = (DjangoModelPermissions,)
queryset = Subnet.objects.all()


class IpAddressView(RetrieveUpdateDestroyAPIView):
class IpAddressView(ProtectedAPIMixin, RetrieveUpdateDestroyAPIView):
serializer_class = IpAddressSerializer
authentication_classes = (BearerAuthentication, SessionAuthentication)
permission_classes = (DjangoModelPermissions,)
queryset = IpAddress.objects.all()


class RequestIPView(CreateAPIView):
class RequestIPView(ProtectedAPIMixin, CreateAPIView):
subnet_model = Subnet
queryset = IpAddress.objects.none()
serializer_class = IpRequestSerializer
authentication_classes = (BearerAuthentication, SessionAuthentication)
permission_classes = (DjangoModelPermissions,)

def post(self, request, *args, **kwargs):
options = {'description': request.data.get('description')}
Expand All @@ -202,12 +196,10 @@ def post(self, request, *args, **kwargs):
return Response(None)


class ImportSubnetView(CreateAPIView):
class ImportSubnetView(ProtectedAPIMixin, CreateAPIView):
subnet_model = Subnet
queryset = Subnet.objects.none()
serializer_class = ImportSubnetSerializer
authentication_classes = (BearerAuthentication, SessionAuthentication)
permission_classes = (DjangoModelPermissions,)

def post(self, request, *args, **kwargs):
file = request.FILES['csvfile']
Expand All @@ -220,12 +212,10 @@ def post(self, request, *args, **kwargs):
return Response({'detail': _('Data imported successfully.')})


class ExportSubnetView(CreateAPIView):
class ExportSubnetView(ProtectedAPIMixin, CreateAPIView):
subnet_model = Subnet
queryset = Subnet.objects.none()
serializer_class = serializers.Serializer
authentication_classes = (BearerAuthentication, SessionAuthentication)
permission_classes = (DjangoModelPermissions,)

def post(self, request, *args, **kwargs):
response = HttpResponse(content_type='text/csv')
Expand All @@ -235,12 +225,10 @@ def post(self, request, *args, **kwargs):
return response


class SubnetHostsView(ListAPIView):
class SubnetHostsView(ProtectedAPIMixin, ListAPIView):
subnet_model = Subnet
queryset = Subnet.objects.none()
serializer_class = HostsResponseSerializer
authentication_classes = (BearerAuthentication, SessionAuthentication)
permission_classes = (DjangoModelPermissions,)
pagination_class = HostsListPagination

def get_queryset(self):
Expand Down
8 changes: 7 additions & 1 deletion openwisp_ipam/apps.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from openwisp_utils.api.apps import ApiAppConfig
from openwisp_utils.utils import register_menu_items
from openwisp_utils.utils import default_or_test, register_menu_items
from swapper import get_model_name

from .compat import patch_ipaddress_lib
Expand All @@ -9,7 +9,13 @@ class OpenWispIpamConfig(ApiAppConfig):
name = 'openwisp_ipam'
verbose_name = 'IPAM'

API_ENABLED = True
REST_FRAMEWORK_SETTINGS = {
'DEFAULT_THROTTLE_RATES': {'ipam': default_or_test('400/hour', None)},
}

def ready(self, *args, **kwargs):
super().ready(*args, **kwargs)
patch_ipaddress_lib()
items = [
{'model': get_model_name('openwisp_ipam', 'Subnet')},
Expand Down

0 comments on commit 043a06d

Please sign in to comment.