diff --git a/example/tests/test_parsers.py b/example/tests/test_parsers.py index 9da1f09c..00d2ca69 100644 --- a/example/tests/test_parsers.py +++ b/example/tests/test_parsers.py @@ -1,7 +1,9 @@ import json +from io import BytesIO from django.test import TestCase -from io import BytesIO +from rest_framework.exceptions import ParseError + from rest_framework_json_api.parsers import JSONParser @@ -36,3 +38,13 @@ def test_parse_include_metadata(self): data = parser.parse(stream, None, self.parser_context) self.assertEqual(data['_meta'], {'random_key': 'random_value'}) + + + def test_parse_include_metadata(self): + parser = JSONParser() + + string = json.dumps([]) + stream = BytesIO(string.encode('utf-8')) + + with self.assertRaises(ParseError): + parser.parse(stream, None, self.parser_context) diff --git a/rest_framework_json_api/parsers.py b/rest_framework_json_api/parsers.py index 6dd12a87..c46a4ab6 100644 --- a/rest_framework_json_api/parsers.py +++ b/rest_framework_json_api/parsers.py @@ -59,44 +59,44 @@ def parse(self, stream, media_type=None, parser_context=None): Parses the incoming bytestream as JSON and returns the resulting data """ result = super(JSONParser, self).parse(stream, media_type=media_type, parser_context=parser_context) - data = result.get('data') - if data: - from rest_framework_json_api.views import RelationshipView - if isinstance(parser_context['view'], RelationshipView): - # We skip parsing the object as JSONAPI Resource Identifier Object and not a regular Resource Object - if isinstance(data, list): - for resource_identifier_object in data: - if not (resource_identifier_object.get('id') and resource_identifier_object.get('type')): - raise ParseError( - 'Received data contains one or more malformed JSONAPI Resource Identifier Object(s)' - ) - elif not (data.get('id') and data.get('type')): - raise ParseError('Received data is not a valid JSONAPI Resource Identifier Object') - - return data - - request = parser_context.get('request') - - # Check for inconsistencies - resource_name = utils.get_resource_name(parser_context) - if data.get('type') != resource_name and request.method in ('PUT', 'POST', 'PATCH'): - raise exceptions.Conflict( - "The resource object's type ({data_type}) is not the type " - "that constitute the collection represented by the endpoint ({resource_type}).".format( - data_type=data.get('type'), - resource_type=resource_name - ) - ) - if not data.get('id') and request.method in ('PATCH', 'PUT'): - raise ParseError("The resource identifier object must contain an 'id' member") + if not isinstance(result, dict) or 'data' not in result: + raise ParseError('Received document does not contain primary data') - # Construct the return data - parsed_data = {'id': data.get('id')} if 'id' in data else {} - parsed_data.update(self.parse_attributes(data)) - parsed_data.update(self.parse_relationships(data)) - parsed_data.update(self.parse_metadata(result)) - return parsed_data + data = result.get('data') - else: - raise ParseError('Received document does not contain primary data') + from rest_framework_json_api.views import RelationshipView + if isinstance(parser_context['view'], RelationshipView): + # We skip parsing the object as JSONAPI Resource Identifier Object and not a regular Resource Object + if isinstance(data, list): + for resource_identifier_object in data: + if not (resource_identifier_object.get('id') and resource_identifier_object.get('type')): + raise ParseError( + 'Received data contains one or more malformed JSONAPI Resource Identifier Object(s)' + ) + elif not (data.get('id') and data.get('type')): + raise ParseError('Received data is not a valid JSONAPI Resource Identifier Object') + + return data + + request = parser_context.get('request') + + # Check for inconsistencies + resource_name = utils.get_resource_name(parser_context) + if data.get('type') != resource_name and request.method in ('PUT', 'POST', 'PATCH'): + raise exceptions.Conflict( + "The resource object's type ({data_type}) is not the type " + "that constitute the collection represented by the endpoint ({resource_type}).".format( + data_type=data.get('type'), + resource_type=resource_name + ) + ) + if not data.get('id') and request.method in ('PATCH', 'PUT'): + raise ParseError("The resource identifier object must contain an 'id' member") + + # Construct the return data + parsed_data = {'id': data.get('id')} if 'id' in data else {} + parsed_data.update(self.parse_attributes(data)) + parsed_data.update(self.parse_relationships(data)) + parsed_data.update(self.parse_metadata(result)) + return parsed_data