Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 44b1f68

Browse files
josebamasliverc
authored andcommitted
Add code to error object if ErrorDetail has code (#700)
1 parent 252d164 commit 44b1f68

File tree

7 files changed

+34
-37
lines changed

7 files changed

+34
-37
lines changed

‎AUTHORS‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,4 @@ Beni Keller <beni@matraxi.ch>
2525
Stas S. <stas@nerd.ro>
2626
Nathanael Gordon <nathanael.l.gordon@gmail.com>
2727
Charlie Allatson <charles.allatson@gmail.com>
28+
Joseba Mendivil <git@jma.email>

‎CHANGELOG.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ This release is not backwards compatible. For easy migration best upgrade first
1616
### Added
1717

1818
* Add support for Django REST framework 3.10.
19+
* Add code from ErrorDetail into the JSON:API error object
1920

2021
### Removed
2122

‎example/tests/test_generic_validation.py‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ def test_generic_validation_error(self):
2525
'source': {
2626
'pointer': '/data'
2727
},
28-
'detail': 'Oh nohs!'
28+
'detail': 'Oh nohs!',
29+
'code': 'invalid',
2930
}]
3031
}
3132

‎example/tests/test_generic_viewset.py‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,13 +65,15 @@ def test_default_validation_exceptions(self):
6565
'pointer': '/data/attributes/email',
6666
},
6767
'detail': 'Enter a valid email address.',
68+
'code': 'invalid',
6869
},
6970
{
7071
'status': '400',
7172
'source': {
7273
'pointer': '/data/attributes/first-name',
7374
},
7475
'detail': 'There\'s a problem with first name',
76+
'code': 'invalid',
7577
}
7678
]
7779
}
@@ -104,6 +106,7 @@ def test_custom_validation_exceptions(self):
104106
'pointer': '/data/attributes/email',
105107
},
106108
'detail': 'Enter a valid email address.',
109+
'code': 'invalid',
107110
},
108111
]
109112
}

‎example/tests/test_model_viewsets.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ def test_404_error_pointer(self):
217217
not_found_url = reverse('user-detail', kwargs={'pk': 12345})
218218
errors = {
219219
'errors': [
220-
{'detail': 'Not found.', 'status': '404'}
220+
{'detail': 'Not found.', 'status': '404', 'code': 'not_found'}
221221
]
222222
}
223223

‎example/tests/test_views.py‎

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,8 @@ def test_if_returns_error_on_empty_post(self):
432432
expected = [{
433433
'detail': 'Received document does not contain primary data',
434434
'status': '400',
435-
'source': {'pointer': '/data'}
435+
'source': {'pointer': '/data'},
436+
'code': 'parse_error',
436437
}]
437438
self.assertEqual(expected, response.data)
438439

@@ -443,7 +444,8 @@ def test_if_returns_error_on_missing_form_data_post(self):
443444
expected = [{
444445
'status': '400',
445446
'detail': 'This field is required.',
446-
'source': {'pointer': '/data/attributes/name'}
447+
'source': {'pointer': '/data/attributes/name'},
448+
'code': 'required',
447449
}]
448450
self.assertEqual(expected, response.data)
449451

@@ -457,7 +459,8 @@ def test_if_returns_error_on_bad_endpoint_name(self):
457459
"represented by the endpoint (blogs)."
458460
),
459461
'source': {'pointer': '/data'},
460-
'status': '409'
462+
'status': '409',
463+
'code': 'error',
461464
}]
462465
self.assertEqual(expected, response.data)
463466

‎rest_framework_json_api/utils.py‎

Lines changed: 20 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -308,13 +308,7 @@ def format_drf_errors(response, context, exc):
308308
# handle generic errors. ValidationError('test') in a view for example
309309
if isinstance(response.data, list):
310310
for message in response.data:
311-
errors.append({
312-
'detail': message,
313-
'source': {
314-
'pointer': '/data',
315-
},
316-
'status': encoding.force_text(response.status_code),
317-
})
311+
errors.append(format_error_object(message, '/data', response))
318312
# handle all errors thrown from serializers
319313
else:
320314
for field, error in response.data.items():
@@ -325,46 +319,40 @@ def format_drf_errors(response, context, exc):
325319
errors.append(error)
326320
elif isinstance(exc, Http404) and isinstance(error, str):
327321
# 404 errors don't have a pointer
328-
errors.append({
329-
'detail': error,
330-
'status': encoding.force_text(response.status_code),
331-
})
322+
errors.append(format_error_object(error, None, response))
332323
elif isinstance(error, str):
333324
classes = inspect.getmembers(exceptions, inspect.isclass)
334325
# DRF sets the `field` to 'detail' for its own exceptions
335326
if isinstance(exc, tuple(x[1] for x in classes)):
336327
pointer = '/data'
337-
errors.append({
338-
'detail': error,
339-
'source': {
340-
'pointer': pointer,
341-
},
342-
'status': encoding.force_text(response.status_code),
343-
})
328+
errors.append(format_error_object(error, pointer, response))
344329
elif isinstance(error, list):
345330
for message in error:
346-
errors.append({
347-
'detail': message,
348-
'source': {
349-
'pointer': pointer,
350-
},
351-
'status': encoding.force_text(response.status_code),
352-
})
331+
errors.append(format_error_object(message, pointer, response))
353332
else:
354-
errors.append({
355-
'detail': error,
356-
'source': {
357-
'pointer': pointer,
358-
},
359-
'status': encoding.force_text(response.status_code),
360-
})
333+
errors.append(format_error_object(error, pointer, response))
361334

362335
context['view'].resource_name = 'errors'
363336
response.data = errors
364337

365338
return response
366339

367340

341+
def format_error_object(message, pointer, response):
342+
error_obj = {
343+
'detail': message,
344+
'status': encoding.force_text(response.status_code),
345+
}
346+
if pointer is not None:
347+
error_obj['source'] = {
348+
'pointer': pointer,
349+
}
350+
code = getattr(message, "code", None)
351+
if code is not None:
352+
error_obj['code'] = code
353+
return error_obj
354+
355+
368356
def format_errors(data):
369357
if len(data) > 1 and isinstance(data, list):
370358
data.sort(key=lambda x: x.get('source', {}).get('pointer', ''))

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /