1. Introduction
When building APIs in Django, having a structured response format improves consistency and maintainability. In this post, we’ll set up a simple API response template to standardize success and error responses in Django REST framework.
2. The Problem
First, we create a new Django project and install Django REST framework. See the demo code:
python3 -m django startproject api_template_response
cd api_template_response
python3 -m venv env
source env/bin/activate
pip install djangorestframework
Add rest_framework
to your INSTALLED_APPS
setting:
INSTALLED_APPS = [
...
'rest_framework',
]
Example User API Response
Consider the following Django API view for fetching user data:
class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = User
fields = ['url', 'username', 'email', 'is_staff']
class UserAPIView(views.APIView):
def get(self, request):
users = User.objects.all()
serializer = UserSerializer(users, many=True, context={'request': request})
return Response(serializer.data)
This API returns:
{
"url": "http://127.0.0.1:8000/api/users/1/",
"username": "admin",
"email": "",
"is_staff": true
}
However, many projects prefer using a standardized API response template, such as:
{
"success": true,
"version": "1.0.0",
"data": {
"url": "http://127.0.0.1:8000/api/users/1/",
"username": "admin",
"email": "",
"is_staff": true
}
}
3. API Response Template
To achieve this, we create a helper function for consistent API responses:
def handle_200_response(data):
response_data = {
"version": "1.0.0",
"status": True,
"data": data,
}
return Response(response_data, status=200)
Using this function ensures all success responses follow the same format. However, if you are using Django ViewSets, manually overriding every function (list
, create
, destroy
, etc.) can become complex.
4. Applying the Template to All APIs
Django REST Framework provides custom renderers that allow us to modify API responses globally. Let's create a custom renderer:
# api_template_response/renderers.py
from rest_framework.renderers import JSONRenderer
from rest_framework import status
class CoreRenderer(JSONRenderer):
def render(self, data, accepted_media_type=None, renderer_context=None):
status_code = renderer_context["response"].status_code
is_success = status.is_success(status_code)
response_data = {
"status": is_success,
"version": "1.0.0",
}
if is_success:
response_data["data"] = data
else:
response_data["error"] = data
return super().render(response_data, accepted_media_type, renderer_context)
Then, configure Django REST Framework to use this renderer globally in settings.py
:
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': [
'api_template_response.renderers.CoreRenderer'
]
}
Testing with JWT Authentication
Now, let's add JWT authentication by installing djangorestframework-simplejwt
:
pip install djangorestframework-simplejwt
Then, configure the authentication endpoints in urls.py
:
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
urlpatterns = [
...
path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
]
Example API Responses
Failed Token Request
curl --location --request POST 'http://127.0.0.1:8000/api/token/'
Response:
{
"status": false,
"version": "1.0.0",
"error": {
"username": ["This field is required."],
"password": ["This field is required."]
}
}
Successful Token Request
curl --location --request POST 'http://127.0.0.1:8000/api/token/' \
--header 'Content-Type: application/json' \
--data-raw '{
"username": "admin",
"password": "admin"
}'
Response:
{
"status": true,
"version": "1.0.0",
"data": {
"refresh": "<JWT_REFRESH_TOKEN>",
"access": "<JWT_ACCESS_TOKEN>"
}
}
Adding Authentication to the ViewSet
from rest_framework.permissions import IsAuthenticated
class UserViewSet(viewsets.ModelViewSet):
permission_classes = [IsAuthenticated]
queryset = User.objects.all()
serializer_class = UserSerializer
If authentication fails, the response will be:
{
"status": false,
"version": "1.0.0",
"error": {
"detail": "Authentication credentials were not provided."
}
}
If successful:
{
"status": true,
"version": "1.0.0",
"data": {
"url": "http://127.0.0.1:8000/api/users/1/",
"username": "admin",
"email": "",
"is_staff": true
}
}
Conclusion
Using a structured API response template enhances consistency, simplifies debugging, and improves API usability. Implement this approach in your Django project to maintain clean and predictable API responses.
See the demo code.
Top comments (0)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.