[Answered ]-Overwrite django rest default validation errors handler

1👍

We can achieve it by writing a custom exception handler.

Here is how a custom response might look like:

{
    "status_code": 400,
    "type": "ValidationError",
    "message": "Bad request syntax or unsupported method",
    "errors": [
        "username: This field may not be null.",
        "email: This field may not be null.",
        "ticket number: This field may not be null."
    ]
}

We have to create a file: exception_handler.py in our project directory with the code that follows; I use utils for this kind of purposes. You can also put this code anywhere you like, but I prefer to have it in a separated file dedicated for this purpose.

from http import HTTPStatus

from rest_framework import exceptions
from rest_framework.views import Response, exception_handler


def api_exception_handler(exception: Exception, context: dict) -> Response:
    """Custom API exception handler."""

    # Call REST framework's default exception handler first,
    # to get the standard error response.
    response = exception_handler(exception, context)

    # Only alter the response when it's a validation error
    if not isinstance(exception, exceptions.ValidationError):
        return response

    # It's a validation error, there should be a Serializer
    view = context.get("view", None)
    serializer = view.get_serializer_class()()

    errors_list = []
    for key, details in response.data.items():

        if key in serializer.fields:
            label = serializer.fields[key].label
            help_text = serializer.fields[key].help_text

            for message in details:
                errors_list.append("{}: {}".format(label, message))

        elif key == "non_field_errors":
            for message in details:
                errors_list.append(message)

        else:
            for message in details:
                errors_list.append("{}: {}".format(key, message))

    # Using the description's of the HTTPStatus class as error message.
    http_code_to_message = {v.value: v.description for v in HTTPStatus}

    error_payload = {
        "status_code": 0,
        "type": "ValidationError",
        "message": "",
        "errors": [],
    }

    #  error = error_payload["error"]
    status_code = response.status_code

    error_payload["status_code"] = status_code
    error_payload["message"] = http_code_to_message[status_code]
    error_payload["errors"] = errors_list

    # Overwrite default exception_handler response data
    response.data = error_payload

    return response

The main idea comes from here, but I changed it to my needs. change it as you see fit.

Don’t forget to set it as your default exception handler in you settings.py file:

REST_FRAMEWORK["EXCEPTION_HANDLER"] = "utils.exception_handler.api_exception_handler";

Leave a comment