Enhance API response handling and implement unified API standard across multiple modules. Added feature flags for unified exception handling and debug throttling in settings. Updated pagination and response formats in various viewsets to align with the new standard. Improved error handling and response validation in frontend components for better user feedback.

This commit is contained in:
IGNY8 VPS (Salman)
2025-11-15 20:18:42 +00:00
parent 94f243f4a2
commit a75ebf2584
18 changed files with 1974 additions and 642 deletions

View File

@@ -0,0 +1,152 @@
"""
Unified API Response Helpers
Provides consistent response format across all endpoints
"""
from rest_framework.response import Response
from rest_framework import status
import uuid
def get_request_id(request):
"""Get request ID from request object (set by middleware) or headers, or generate new one"""
if not request:
return None
# First check if middleware set request_id on request object
if hasattr(request, 'request_id') and request.request_id:
return request.request_id
# Fallback to headers
if hasattr(request, 'META'):
request_id = request.META.get('HTTP_X_REQUEST_ID') or request.META.get('X-Request-ID')
if request_id:
return request_id
# Generate new request ID if none found
return str(uuid.uuid4())
def success_response(data=None, message=None, status_code=status.HTTP_200_OK, request=None):
"""
Create a standardized success response
Args:
data: Response data (dict, list, or None)
message: Optional success message
status_code: HTTP status code (default: 200)
request: Request object (optional, for request_id)
Returns:
Response object with unified format
"""
response_data = {
'success': True,
}
if data is not None:
response_data['data'] = data
if message:
response_data['message'] = message
# Add request_id if request is provided
if request:
response_data['request_id'] = get_request_id(request)
return Response(response_data, status=status_code)
def error_response(error=None, errors=None, status_code=status.HTTP_400_BAD_REQUEST, request=None, debug_info=None):
"""
Create a standardized error response
Args:
error: Top-level error message
errors: Field-specific errors (dict of field -> list of errors)
status_code: HTTP status code (default: 400)
request: Request object (optional, for request_id)
debug_info: Debug information (only in DEBUG mode)
Returns:
Response object with unified error format
"""
response_data = {
'success': False,
}
if error:
response_data['error'] = error
elif status_code == status.HTTP_400_BAD_REQUEST:
response_data['error'] = 'Bad request'
elif status_code == status.HTTP_401_UNAUTHORIZED:
response_data['error'] = 'Authentication required'
elif status_code == status.HTTP_403_FORBIDDEN:
response_data['error'] = 'Permission denied'
elif status_code == status.HTTP_404_NOT_FOUND:
response_data['error'] = 'Resource not found'
elif status_code == status.HTTP_409_CONFLICT:
response_data['error'] = 'Conflict'
elif status_code == status.HTTP_422_UNPROCESSABLE_ENTITY:
response_data['error'] = 'Validation failed'
elif status_code == status.HTTP_429_TOO_MANY_REQUESTS:
response_data['error'] = 'Rate limit exceeded'
elif status_code >= 500:
response_data['error'] = 'Internal server error'
else:
response_data['error'] = 'An error occurred'
if errors:
response_data['errors'] = errors
# Add request_id if request is provided
if request:
response_data['request_id'] = get_request_id(request)
# Add debug info in DEBUG mode
if debug_info:
response_data['debug'] = debug_info
return Response(response_data, status=status_code)
def paginated_response(paginated_data, message=None, request=None):
"""
Create a standardized paginated response
Args:
paginated_data: Paginated data dict from DRF paginator (contains count, next, previous, results)
message: Optional success message
request: Request object (optional, for request_id)
Returns:
Response object with unified paginated format
"""
response_data = {
'success': True,
}
# Copy pagination fields from DRF paginator
if isinstance(paginated_data, dict):
response_data.update({
'count': paginated_data.get('count', 0),
'next': paginated_data.get('next'),
'previous': paginated_data.get('previous'),
'results': paginated_data.get('results', [])
})
else:
# Fallback if paginated_data is not a dict
response_data['count'] = 0
response_data['next'] = None
response_data['previous'] = None
response_data['results'] = []
if message:
response_data['message'] = message
# Add request_id if request is provided
if request:
response_data['request_id'] = get_request_id(request)
return Response(response_data, status=status.HTTP_200_OK)