# ----------------------------------
# middleware.py
# ----------------------------------
import json
import copy
from django.utils.deprecation import MiddlewareMixin
from django.utils.translation import ugettext_lazy as _
from django.core.serializers.json import DjangoJSONEncoder
from rest_framework import status
class BaseAPIResponseMiddleware(MiddlewareMixin):
def render_response(self, response):
"""
function to fixed the response API following with this format:
[1] success single
{
"status": 200,
"success": true,
"message": "The success message",
"result": {}
}
[2] success list
{
"status": 200,
"success": true,
"message": null,
"results": [],
"count": 2,
"page_size": 5,
"current_page": 1,
"next": "http://127.0.0.1:8000/api/page/?page=2&search=a",
"previous": null
}
[3] failed
{
"status": 400,
"success": false,
"message": "The failed message",
"result": {}
}
"""
default_response_keys = ('status', 'status_http', 'detail', 'message',
'success', 'non_field_errors', 'count',
'page_size', 'current_page', 'next',
'previous', 'result', 'results')
response_data = copy.deepcopy(response.data)
# setup default result if doesn't exist
if not any(['result' in response_data, 'results' in response_data]):
response_data.update({'result': {}})
# setup default message into response data
if 'message' not in response_data:
response_data.update({'message': None})
# store the status_code into response data
if 'status' not in response_data:
response_data.update({'status': response.status_code})
# store the status_http into response data
if 'status_http' not in response_data:
response_data.update({'status_http': response.status_code})
# updating the response message
if 'detail' in response_data:
response_data.update({'message': response_data.get('detail')})
del response_data['detail']
elif 'non_field_errors' in response_data:
response_errors = '
'.join(response_data.get('non_field_errors'))
response_data.update({'message': response_errors})
del response_data['non_field_errors']
# store the success boolean into response data
if response.status_code >= 400:
response_errors = []
response_errors_keys = []
for (key, value) in response_data.items():
if key not in default_response_keys:
errors = ' '.join([str(v) for v in value])
errors = '%s: %s' % (key, errors)
response_errors.append(errors)
response_errors_keys.append(key)
if len(response_errors) > 0:
response_errors = '
'.join(response_errors)
response_data.update({'message': response_errors})
# deleting the errors in the field keys.
if len(response_errors_keys) > 0:
list(map(response_data.pop, response_errors_keys))
if not response_data.get('message'):
response_data.update({'message': _('Failed')})
response_data.update({'success': False,
'status_http': status.HTTP_200_OK})
elif response.status_code >= 100:
if not response_data.get('message'):
response_data.update({'message': _('Success')})
if 'success' not in response_data:
response_data.update({'success': True})
return response_data
def process_response(self, request, response):
if hasattr(response, 'data') and isinstance(response.data, dict):
try:
response_data = self.render_response(response)
response.status_code = response_data.get('status_http')
if 'status_http' in response_data:
del response_data['status_http']
response.data = response_data
response.content = json.dumps(response_data, cls=DjangoJSONEncoder)
except Exception:
pass
return response
# --------------------------------------------------------------------
# paginator.py
# --------------------------------------------------------------------
from __future__ import unicode_literals
from collections import OrderedDict
from django.conf import settings
from django.core.paginator import (Paginator, EmptyPage, PageNotAnInteger)
from django.utils.translation import ugettext_lazy as _
from rest_framework import status
from rest_framework.response import Response
from rest_framework.pagination import (PageNumberPagination, LimitOffsetPagination)
class RestPagination(PageNumberPagination, LimitOffsetPagination):
"""
class FoobarPagiantion(RestPagination):
page_size = 10
class FoobarView(ListAPIView):
pagination_class = FoobarPagiantion
"""
def paginate_queryset(self, queryset, request, view=None):
queryset = super().paginate_queryset(queryset, request, view=view)
limit = request.query_params.get('limit')
if str(limit).isdigit():
return queryset[:int(limit)]
return queryset
def get_paginated_response(self, results):
next_link = self.get_next_link() if self.get_next_link() is not None else ''
prev_link = self.get_previous_link() if self.get_previous_link() is not None else ''
if settings.USE_SSL:
next_link = next_link.replace('http:', 'https:')
prev_link = prev_link.replace('http:', 'https:')
return Response(OrderedDict([
('count', self.page.paginator.count),
('page_size', self.page_size),
('current_page', self.page.number),
('next', next_link if next_link != '' else None),
('previous', prev_link if prev_link != '' else None),
('status', status.HTTP_200_OK),
('message', _('Success')),
('success', True),
('results', results)
]))
# --------------------------------------------------------------------
# settings.py
# --------------------------------------------------------------------
"""
MIDDLEWARE = [
....
'path.to.middleware.BaseAPIResponseMiddleware'
]
REST_FRAMEWORK = {
....
'DEFAULT_PAGINATION_CLASS': 'path.to.paginator.RestPagination'
}
"""