Skip to content

Commit

Permalink
Add custom exception handler for standardized error responses
Browse files Browse the repository at this point in the history
- Replace 'detail' with 'message' for error consistency
- Format error messages into a single readable string
- Handle cases without a response using a generic error

Ensures all responses follow the project's SuccessResponse format.
  • Loading branch information
QuvonchbekBobojonov committed Jan 15, 2025
1 parent 3187398 commit 14ce99d
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 17 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ from rest_framework.views import APIView
class MyView(APIView):
@staticmethod
def get(request):
data = {'detail': 'error'}
data = {'message': 'error'}
return SuccessResponse(data, success=False)
```

Expand All @@ -64,8 +64,8 @@ class MyView(APIView):
```json
{
"success": false,
"result": {
"detail": "error"
"error": {
"message": "error"
}
}
```
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

setup(
name="django-success-response",
version="1.0.5",
version="1.1.0",
description="Django app for customizing response",
author="Quvonchbek Bobojonov",
author_email="[email protected]",
Expand Down
7 changes: 5 additions & 2 deletions src/success_response/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ def __init__(self, detail=None, code=None, success=False):
:param success: Optional flag to indicate success (default: False).
"""
# Customize the detail structure to include the 'success' key along with the error result.
detail = {'success': success, 'result': detail}
detail = {'success': success, 'error': {
'code': code,
'message': detail,
}}

# Call the parent constructor with the custom detail structure.
super().__init__(detail, code)
super().__init__(detail, drf_status.HTTP_200_OK)
10 changes: 8 additions & 2 deletions src/success_response/response.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,16 @@
# Custom response class that standardizes API responses with an additional
# 'success' field, indicating success or failure, and a 'result' field holding the actual data.
class SuccessResponse(Response):
def __init__(self, data=None, headers=None, exception=False, content_type=None, success=True):
def __init__(self, data=None, headers=None, exception=False, content_type=None, success=True, status=drf_status.HTTP_400_BAD_REQUEST):
# Wrap the data in a standardized format with 'success' indicating success status,
# and 'result' containing the response payload.
data = {'success': success, 'result': data}
if success:
data = {'success': success, 'result': data}
else:
data = {'success': success, 'error': {
'code': status
**data
}}

# Default the status code to 200 (OK) unless otherwise specified.
status = drf_status.HTTP_200_OK
Expand Down
30 changes: 21 additions & 9 deletions src/success_response/views.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from rest_framework.views import exception_handler
from rest_framework import status
from django.utils.translation import gettext_lazy as _
from .response import SuccessResponse


def success_exception_handler(exc, context):
"""
Custom exception handler to format all error responses using SuccessResponse.
Expand All @@ -16,19 +17,30 @@ def success_exception_handler(exc, context):
if response is not None:
data = response.data

# Check if 'detail' key exists, otherwise format error messages.
if 'detail' not in data:
# If 'detail' is missing, combine all error messages into a single string.
# For each key in data, join associated errors into a string.
data = {'detail': ' '.join(f"{key}: {' '.join(errors)}" for key, errors in data.items())}
# Replace 'detail' key with 'message' if it exists.
if 'detail' in data:
data['message'] = data.pop('detail')

# If neither 'detail' nor 'message' exists, format the error messages.
if 'message' not in data:
data = {
'message': ' '.join(
f"{key}: {' '.join(errors)}" for key, errors in data.items()
)
}

# Wrap the error response in a standardized format using SuccessResponse.
response = SuccessResponse(data, success=False)
response = SuccessResponse(
data,
success=False,
status=response.status_code
)
else:
# If DRF doesn't provide a response, return a generic internal server error response.
# Handle cases with no response by returning a generic error response.
response = SuccessResponse(
{'detail': 'Internal Server Error'},
{'message': _('Internal Server Error')},
success=False,
status=status.HTTP_500_INTERNAL_SERVER_ERROR
)

return response

0 comments on commit 14ce99d

Please sign in to comment.