diff --git a/todo/exceptions/exception_handler.py b/todo/exceptions/exception_handler.py new file mode 100644 index 0000000..397ef6c --- /dev/null +++ b/todo/exceptions/exception_handler.py @@ -0,0 +1,36 @@ +from typing import List +from rest_framework.exceptions import ValidationError +from rest_framework.response import Response +from rest_framework import status +from rest_framework.views import exception_handler +from rest_framework.utils.serializer_helpers import ReturnDict + +from todo.dto.responses.error_response import ApiErrorDetail, ApiErrorResponse, ApiErrorSource + + +def handle_exception(exc, context): + if isinstance(exc, ValidationError): + return Response( + ApiErrorResponse( + statusCode=status.HTTP_400_BAD_REQUEST, + message="Invalid request", + errors=format_validation_errors(exc.detail), + ).model_dump(mode="json", exclude_none=True), + status=status.HTTP_400_BAD_REQUEST, + ) + return exception_handler(exc, context) + + +def format_validation_errors(errors) -> List[ApiErrorDetail]: + formatted_errors = [] + if isinstance(errors, ReturnDict | dict): + for field, messages in errors.items(): + if isinstance(messages, list): + for message in messages: + formatted_errors.append(ApiErrorDetail(detail=message, source={ApiErrorSource.PARAMETER: field})) + elif isinstance(messages, dict): + nested_errors = format_validation_errors(messages) + formatted_errors.extend(nested_errors) + else: + formatted_errors.append(ApiErrorDetail(detail=messages, source={ApiErrorSource.PARAMETER: field})) + return formatted_errors diff --git a/todo_project/settings/base.py b/todo_project/settings/base.py index 2d4fd9e..194d397 100644 --- a/todo_project/settings/base.py +++ b/todo_project/settings/base.py @@ -49,4 +49,5 @@ "rest_framework.renderers.JSONRenderer", ], "UNAUTHENTICATED_USER": None, + "EXCEPTION_HANDLER": "todo.exceptions.exception_handler.handle_exception", }