Skip to content

Commit 87723e5

Browse files
committed
[django-json-api#214] Extract formatting DRF errors.
1 parent 4bd759a commit 87723e5

File tree

2 files changed

+60
-58
lines changed

2 files changed

+60
-58
lines changed

rest_framework_json_api/exceptions.py

+2-58
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
import inspect
2-
from django.utils import six, encoding
31
from django.utils.translation import ugettext_lazy as _
42
from rest_framework import status, exceptions
53

6-
from rest_framework_json_api.utils import format_value
4+
from rest_framework_json_api import utils
75

86

97
def exception_handler(exc, context):
@@ -18,63 +16,9 @@ def exception_handler(exc, context):
1816

1917
if not response:
2018
return response
21-
22-
errors = []
23-
# handle generic errors. ValidationError('test') in a view for example
24-
if isinstance(response.data, list):
25-
for message in response.data:
26-
errors.append({
27-
'detail': message,
28-
'source': {
29-
'pointer': '/data',
30-
},
31-
'status': encoding.force_text(response.status_code),
32-
})
33-
# handle all errors thrown from serializers
34-
else:
35-
for field, error in response.data.items():
36-
field = format_value(field)
37-
pointer = '/data/attributes/{}'.format(field)
38-
# see if they passed a dictionary to ValidationError manually
39-
if isinstance(error, dict):
40-
errors.append(error)
41-
elif isinstance(error, six.string_types):
42-
classes = inspect.getmembers(exceptions, inspect.isclass)
43-
# DRF sets the `field` to 'detail' for its own exceptions
44-
if isinstance(exc, tuple(x[1] for x in classes)):
45-
pointer = '/data'
46-
errors.append({
47-
'detail': error,
48-
'source': {
49-
'pointer': pointer,
50-
},
51-
'status': encoding.force_text(response.status_code),
52-
})
53-
elif isinstance(error, list):
54-
for message in error:
55-
errors.append({
56-
'detail': message,
57-
'source': {
58-
'pointer': pointer,
59-
},
60-
'status': encoding.force_text(response.status_code),
61-
})
62-
else:
63-
errors.append({
64-
'detail': error,
65-
'source': {
66-
'pointer': pointer,
67-
},
68-
'status': encoding.force_text(response.status_code),
69-
})
70-
71-
72-
context['view'].resource_name = 'errors'
73-
response.data = errors
74-
return response
19+
return utils.format_drf_errors(response, context, exc)
7520

7621

7722
class Conflict(exceptions.APIException):
7823
status_code = status.HTTP_409_CONFLICT
7924
default_detail = _('Conflict.')
80-

rest_framework_json_api/utils.py

+58
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,16 @@
33
"""
44
import copy
55
from collections import OrderedDict
6+
import inspect
67

78
import inflection
89
from django.conf import settings
10+
from django.utils import encoding
911
from django.utils import six
1012
from django.utils.module_loading import import_string as import_class_from_dotted_path
1113
from django.utils.translation import ugettext_lazy as _
1214
from rest_framework.exceptions import APIException
15+
from rest_framework import exceptions
1316

1417
try:
1518
from rest_framework.serializers import ManyRelatedField
@@ -249,3 +252,58 @@ def __new__(self, url, name):
249252
return ret
250253

251254
is_hyperlink = True
255+
256+
257+
def format_drf_errors(response, context, exc):
258+
errors = []
259+
# handle generic errors. ValidationError('test') in a view for example
260+
if isinstance(response.data, list):
261+
for message in response.data:
262+
errors.append({
263+
'detail': message,
264+
'source': {
265+
'pointer': '/data',
266+
},
267+
'status': encoding.force_text(response.status_code),
268+
})
269+
# handle all errors thrown from serializers
270+
else:
271+
for field, error in response.data.items():
272+
field = format_value(field)
273+
pointer = '/data/attributes/{}'.format(field)
274+
# see if they passed a dictionary to ValidationError manually
275+
if isinstance(error, dict):
276+
errors.append(error)
277+
elif isinstance(error, six.string_types):
278+
classes = inspect.getmembers(exceptions, inspect.isclass)
279+
# DRF sets the `field` to 'detail' for its own exceptions
280+
if isinstance(exc, tuple(x[1] for x in classes)):
281+
pointer = '/data'
282+
errors.append({
283+
'detail': error,
284+
'source': {
285+
'pointer': pointer,
286+
},
287+
'status': encoding.force_text(response.status_code),
288+
})
289+
elif isinstance(error, list):
290+
for message in error:
291+
errors.append({
292+
'detail': message,
293+
'source': {
294+
'pointer': pointer,
295+
},
296+
'status': encoding.force_text(response.status_code),
297+
})
298+
else:
299+
errors.append({
300+
'detail': error,
301+
'source': {
302+
'pointer': pointer,
303+
},
304+
'status': encoding.force_text(response.status_code),
305+
})
306+
307+
context['view'].resource_name = 'errors'
308+
response.data = errors
309+
return response

0 commit comments

Comments
 (0)