Customizing API Responses

Customizing API Responses in Django Rest Framework (DRF)

When building REST APIs, it’s crucial to ensure that responses are well-structured, informative, and consistent. In this section, we will cover:

  • Returning JSON Responses – How to send structured data back to the client.

  • Customizing Response Format – Formatting the response to include metadata like status and total records.
  • Handling Errors & Exceptions – Ensuring meaningful error messages are returned for better debugging.

Returning JSON Responses

Updating views.py to return a structured JSON response

from rest_framework.views import APIView

from rest_framework.response import Response

from rest_framework import status

from .models import Book

from .serializers import BookSerializer

 

class BookListCustomResponseView(APIView):

    def get(self, request):

        books = Book.objects.all()

        serializer = BookSerializer(books, many=True)

 

        # Customized response format

        response_data = {

            ‘status’: ‘success’,

            ‘total_books’: len(serializer.data),

            ‘books’: serializer.data,

        }

        return Response(response_data, status=status.HTTP_200_OK)

 

Adding URL Path for the Custom Response View (urls.py)

 

from .views import BookListCustomResponseView

 

urlpatterns += [

   path(‘books/custom-list/’, BookListCustomResponseView.as_view(), name=’custom-list’),

]

Explanation:

1. Returning JSON Responses

  • In Django Rest Framework, the Response object is used to return JSON responses.
  • The Response class formats the data properly and ensures the correct content type (application/json).
  • Instead of returning plain serialized data, we structure the response with additional details.

2. Customizing Response Format

  • The API response includes:
    • status: Indicates whether the request was successful.
    • total_books: Provides the count of books in the response.
    • books: Contains the list of books serialized in JSON format.
  • This structure makes it easier for frontend applications or consumers of the API to process the data.

3. Handling Errors & Exceptions

  • If an error occurs (e.g., no books found, invalid request), DRF provides built-in exception handling.

In this case, we return a 200 OK response even if there are no books, but we could modify the logic to return a 404 Not Found or 400 Bad Request if needed.

Example API Response

If there are two books in the database, the API would return:

{

    “status”: “success”,

    “total_books”: 2,

    “books”: [

        {

            “id”: 1,

            “title”: “Django for Beginners”,

            “author”: “William S. Vincent”,

            “price”: 29.99,

            “published_date”: “2023-05-10”

        },

        {

            “id”: 2,

            “title”: “Python API Development”,

            “author”: “John Doe”,

            “price”: 39.99,

            “published_date”: “2024-01-15”

        }

    ]

}

Why Customizing API Responses Matters?

Improved Readability – Makes it easier for API consumers to understand the response.
Standardization—Ensures all responses follow a consistent format.
Better Debugging—Helps in troubleshooting issues by providing extra details like status messages.

Handling Errors & Exceptions in Django Rest Framework (DRF)

While building REST APIs, it’s important to handle errors gracefully and return meaningful responses to API consumers. In this section, we’ll cover:

Handling Errors in API Views
Returning Custom Error Messages
Using DRF’s Built-in Exception Handling

Enhancing views.py with Error Handling

Updated views.py:

from rest_framework.views import APIView

from rest_framework.response import Response

from rest_framework import status

from django.core.exceptions import ObjectDoesNotExist

from .models import Book

from .serializers import BookSerializer

 

class BookListCustomResponseView(APIView):

    def get(self, request):

        try:

            books = Book.objects.all()

            

            # Handle case when no books are found

            if not books.exists():

                return Response(

                    {“status”: “error”, “message”: “No books found”},

                    status=status.HTTP_404_NOT_FOUND

                )

            

            serializer = BookSerializer(books, many=True)

 

            # Customized response format

            response_data = {

                “status”: “success”,

                “total_books”: len(serializer.data),

                “books”: serializer.data,

            }

            return Response(response_data, status=status.HTTP_200_OK)

 

        except Exception as e:

            return Response(

                {“status”: “error”, “message”: str(e)},

                status=status.HTTP_500_INTERNAL_SERVER_ERROR

            )

Adding Custom Error Handling in Django Rest Framework

1. Handling No Records Found (404 Not Found)
  • We check if books.exists() before serialization.

If no records exist, we return:
{

    “status”: “error”,

    “message”: “No books found”

}

  • This prevents returning an empty list without explanation.

     

2. Handling Unexpected Errors (500 Internal Server Error)
  • Any unexpected error is caught using except Exception as e.

     

  • The actual error message is returned in the response.

Example response in case of an unknown error:
{

    “status”: “error”,

    “message”: “Some error occurred”

}

Example API Responses (After Adding Error Handling)

Success Response (Books Found)

{

    “status”: “success”,

    “total_books”: 2,

    “books”: [

        {

            “id”: 1,

            “title”: “Django for Beginners”,

            “author”: “William S. Vincent”,

            “price”: 29.99,

            “published_date”: “2023-05-10”

        },

        {

            “id”: 2,

            “title”: “Python API Development”,

            “author”: “John Doe”,

            “price”: 39.99,

            “published_date”: “2024-01-15”

        }

    ]

}

 Error Response (No Books in Database)

{

    “status”: “error”,

    “message”: “No books found”

}

 Error Response (Unexpected Server Error)

{

    “status”: “error”,

    “message”: “Some error occurred”

}

Why Custom Error Handling Matters?

Improves API Reliability – Prevents unexpected crashes.
Better Developer Experience – Clear error messages make debugging easier.
Enhances API Consumer Experience – Clients can handle errors properly based on response codes.

What Does This Code Do?

After implementing this code:

 

  1. Creates a New API Endpoint

     

    • The new URL /api/books/custom-list/ is added.

       

    • This allows users to send a Get request to create a book.
  1. Returning JSON Responses:

     

  •   The API fetches data from the database and serializes it into a JSON response.

     

  • Instead of returning plain serialized data, the response is structured with metadata like status and count.

     

  1. Customizing Response Format:
  • The BookListCustomResponseView formats the response as { “status”: “success”, “total_books”: <count>, “books”: <data> }.
  1. Handling Errors & Exceptions:
  • If no books exist, a { “status”: “error”, “message”: “No books found” } response is returned with 404 status.

     

If an unexpected error occurs, it returns { “status”: “error”, “message”: “Some error occurred” } with 500 status.

How Does It Work? (Step-by-Step Execution)

1️⃣ Client Makes a GET Request

The client (frontend or API consumer) sends a GET request to /books/custom-list/.Like below:

2️⃣ Django Views Handle the Request

  • The BookListCustomResponseView class receives the request.

3️⃣ Fetch Data from Database

  • Book.objects.all() retrieves all book records from the database.

4️⃣ Serialize the Data

  • The BookSerializer(books, many=True) converts the queryset into JSON format.

5️⃣ Customize the Response

A custom dictionary is created:
{

  “status”: “success”,

  “total_books”: <count>,

  “books”: <data>

}

  • This ensures the response is structured and informative.

6️⃣ Return the Response with HTTP 200 Status

  • The formatted response is returned using Response(response_data, status=status.HTTP_200_OK).

7️⃣ Client Receives the Response

  • The frontend/API consumer receives a JSON response with book details, status, and total count.

✅ If there are no books, an empty list is returned.
✅ If an error occurs, DRF’s built-in exception handling provides a relevant error message.

 

Exception Handling

8️⃣  Handling Missing Data or Empty Queryset

If no books exist, the response still returns a success message with an empty list:
{

  “status”: “success”,

  “total_books”: 0,

  “books”: []

}

9️⃣ Handling 400 Errors (Bad Request)

  • If the request is malformed (e.g., missing required parameters in a POST request), DRF automatically raises a 400 Bad Request response.

Exercise:

  • Override the create() method in your StudentViewSet to return a custom success message.

  • Example: {“message”: “Student created successfully!”}

Course Video in English