diff --git a/rest_framework_json_api/exceptions.py b/rest_framework_json_api/exceptions.py index c581bda2..a4a78b74 100644 --- a/rest_framework_json_api/exceptions.py +++ b/rest_framework_json_api/exceptions.py @@ -1,7 +1,16 @@ +from django.conf import settings from django.utils.translation import ugettext_lazy as _ from rest_framework import status, exceptions from rest_framework_json_api import utils +from rest_framework_json_api import renderers + + +def rendered_with_json_api(view): + for renderer_class in getattr(view, 'renderer_classes', []): + if issubclass(renderer_class, renderers.JSONRenderer): + return True + return False def exception_handler(exc, context): @@ -12,11 +21,26 @@ def exception_handler(exc, context): # # Also see: https://github.com/django-json-api/django-rest-framework-json-api/issues/158 from rest_framework.views import exception_handler as drf_exception_handler - response = drf_exception_handler(exc, context) + # Render exception with DRF + response = drf_exception_handler(exc, context) if not response: return response - return utils.format_drf_errors(response, context, exc) + + # Use regular DRF format if not rendered by DRF JSON API and not uniform + is_json_api_view = rendered_with_json_api(context['view']) + is_uniform = getattr(settings, 'JSON_API_UNIFORM_EXCEPTIONS', False) + if not is_json_api_view and not is_uniform: + return response + + # Convert to DRF JSON API error format + response = utils.format_drf_errors(response, context, exc) + + # Add top-level 'errors' object when not rendered by DRF JSON API + if not is_json_api_view: + response.data = utils.format_errors(response.data) + + return response class Conflict(exceptions.APIException): diff --git a/rest_framework_json_api/renderers.py b/rest_framework_json_api/renderers.py index 518b653e..bd3184e8 100644 --- a/rest_framework_json_api/renderers.py +++ b/rest_framework_json_api/renderers.py @@ -381,11 +381,8 @@ def render_relationship_view(self, data, accepted_media_type=None, renderer_cont ) def render_errors(self, data, accepted_media_type=None, renderer_context=None): - # Get the resource name. - if len(data) > 1 and isinstance(data, list): - data.sort(key=lambda x: x.get('source', {}).get('pointer', '')) return super(JSONRenderer, self).render( - {'errors': data}, accepted_media_type, renderer_context + utils.format_errors(data), accepted_media_type, renderer_context ) def render(self, data, accepted_media_type=None, renderer_context=None): diff --git a/rest_framework_json_api/utils.py b/rest_framework_json_api/utils.py index 88a06ba6..261640c6 100644 --- a/rest_framework_json_api/utils.py +++ b/rest_framework_json_api/utils.py @@ -315,4 +315,11 @@ def format_drf_errors(response, context, exc): context['view'].resource_name = 'errors' response.data = errors + return response + + +def format_errors(data): + if len(data) > 1 and isinstance(data, list): + data.sort(key=lambda x: x.get('source', {}).get('pointer', '')) + return {'errors': data}