diff --git a/CHANGELOG.md b/CHANGELOG.md index e6b257d4..a1b72009 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 Note that in line with [Django REST framework policy](https://www.django-rest-framework.org/topics/release-notes/), any parts of the framework not mentioned in the documentation should generally be considered private API, and may be subject to change. +## [Unreleased] + +### Fixed + +* Fixed invalid relationship pointer in error objects when field naming formatting is used. + ## [5.0.0] - 2022-01-03 This release is not backwards compatible. For easy migration best upgrade first to version diff --git a/example/tests/__snapshots__/test_errors.ambr b/example/tests/__snapshots__/test_errors.ambr index 1ef85ab8..fe872b46 100644 --- a/example/tests/__snapshots__/test_errors.ambr +++ b/example/tests/__snapshots__/test_errors.ambr @@ -47,14 +47,66 @@ ]), }) # --- -# name: test_relationship_errors_has_correct_pointers +# name: test_relationship_errors_has_correct_pointers_with_camelize dict({ 'errors': list([ dict({ 'code': 'incorrect_type', 'detail': 'Incorrect type. Expected resource identifier object, received str.', 'source': dict({ - 'pointer': '/data/relationships/author', + 'pointer': '/data/relationships/authors', + }), + 'status': '400', + }), + dict({ + 'code': 'incorrect_type', + 'detail': 'Incorrect type. Expected resource identifier object, received str.', + 'source': dict({ + 'pointer': '/data/relationships/mainAuthor', + }), + 'status': '400', + }), + ]), + }) +# --- +# name: test_relationship_errors_has_correct_pointers_with_dasherize + dict({ + 'errors': list([ + dict({ + 'code': 'incorrect_type', + 'detail': 'Incorrect type. Expected resource identifier object, received str.', + 'source': dict({ + 'pointer': '/data/relationships/authors', + }), + 'status': '400', + }), + dict({ + 'code': 'incorrect_type', + 'detail': 'Incorrect type. Expected resource identifier object, received str.', + 'source': dict({ + 'pointer': '/data/relationships/main-author', + }), + 'status': '400', + }), + ]), + }) +# --- +# name: test_relationship_errors_has_correct_pointers_with_no_formatting + dict({ + 'errors': list([ + dict({ + 'code': 'incorrect_type', + 'detail': 'Incorrect type. Expected resource identifier object, received str.', + 'source': dict({ + 'pointer': '/data/relationships/authors', + }), + 'status': '400', + }), + dict({ + 'code': 'incorrect_type', + 'detail': 'Incorrect type. Expected resource identifier object, received str.', + 'source': dict({ + 'pointer': '/data/relationships/main_author', }), 'status': '400', }), diff --git a/example/tests/test_errors.py b/example/tests/test_errors.py index 2267ec6e..72e742c7 100644 --- a/example/tests/test_errors.py +++ b/example/tests/test_errors.py @@ -30,9 +30,12 @@ class EntrySerializer(serializers.Serializer): comment = CommentSerializer(required=False) headline = serializers.CharField(allow_null=True, required=True) body_text = serializers.CharField() - author = serializers.ResourceRelatedField( + main_author = serializers.ResourceRelatedField( queryset=Author.objects.all(), required=False ) + authors = serializers.ResourceRelatedField( + queryset=Author.objects.all(), required=False, many=True + ) def validate(self, attrs): body_text = attrs["body_text"] @@ -195,7 +198,31 @@ def test_many_third_level_dict_errors(client, some_blog, snapshot): assert snapshot == perform_error_test(client, data) -def test_relationship_errors_has_correct_pointers(client, some_blog, snapshot): +def test_relationship_errors_has_correct_pointers_with_camelize( + client, some_blog, snapshot +): + data = { + "data": { + "type": "entries", + "attributes": { + "blog": some_blog.pk, + "bodyText": "body_text", + "headline": "headline", + }, + "relationships": { + "mainAuthor": {"data": {"id": "INVALID_ID", "type": "authors"}}, + "authors": {"data": [{"id": "INVALID_ID", "type": "authors"}]}, + }, + } + } + + assert snapshot == perform_error_test(client, data) + + +@override_settings(JSON_API_FORMAT_FIELD_NAMES="dasherize") +def test_relationship_errors_has_correct_pointers_with_dasherize( + client, some_blog, snapshot +): data = { "data": { "type": "entries", @@ -205,7 +232,30 @@ def test_relationship_errors_has_correct_pointers(client, some_blog, snapshot): "headline": "headline", }, "relationships": { - "author": {"data": {"id": "INVALID_ID", "type": "authors"}} + "main-author": {"data": {"id": "INVALID_ID", "type": "authors"}}, + "authors": {"data": [{"id": "INVALID_ID", "type": "authors"}]}, + }, + } + } + + assert snapshot == perform_error_test(client, data) + + +@override_settings(JSON_API_FORMAT_FIELD_NAMES=None) +def test_relationship_errors_has_correct_pointers_with_no_formatting( + client, some_blog, snapshot +): + data = { + "data": { + "type": "entries", + "attributes": { + "blog": some_blog.pk, + "body_text": "body_text", + "headline": "headline", + }, + "relationships": { + "main_author": {"data": {"id": "INVALID_ID", "type": "authors"}}, + "authors": {"data": [{"id": "INVALID_ID", "type": "authors"}]}, }, } } diff --git a/rest_framework_json_api/utils.py b/rest_framework_json_api/utils.py index aba9de5a..8d2dfa73 100644 --- a/rest_framework_json_api/utils.py +++ b/rest_framework_json_api/utils.py @@ -380,7 +380,9 @@ def format_drf_errors(response, context, exc): serializer = context["view"].get_serializer() fields = get_serializer_fields(serializer) or dict() relationship_fields = [ - name for name, field in fields.items() if is_relationship_field(field) + format_field_name(name) + for name, field in fields.items() + if is_relationship_field(field) ] for field, error in response.data.items():