-
Notifications
You must be signed in to change notification settings - Fork 300
-
Currently rest_framework_json_api.parsers.JSONParser only accepts stream-like objects as an input, intended for parsing incoming requests. This is fine and intended behavior for many use-cases.
However, there are edge cases where json:api's specification is limited, e.g. when uploading files along with JSON data. This has been an open discussion for years (see json-api/json-api#246).
One (seemingly widely used) way to achieve this behavior is by sending the data as multipart/form-data and specifying a data field with the JSON data as well as an additional field for files.
This is then handled with a custom parser, inheriting functionality from rest_framework.parsers.MultiPartParser. This works in a similar fashion as the parse method in JSONParser, first running the request data through the parent parser and modifying it to fit the desired schema afterwards.
The issue is that once you received the JSON data from MultiPartParser, there is no function on DRFJA to format that payload. You have to overwrite/copy-paste into your own method to access the parsing functionality after the inital rest_framework.parsers.JSONParser call.
Showing some code might explain it better:
# rest_framework_json_api/parsers.py#JSONParser def parse(self, stream, media_type=None, parser_context=None): # We do not need this result = super().parse( stream, media_type=media_type, parser_context=parser_context ) # We need everything starting from here as a separate method # ... some parsing to specification happening here return parsed_data
This could be achieved by adding an extra method like parse_json, both making it public and using it from within the existing parser method. Building custom parsers for DRFJA would be made a little easier this way. I would be happy to provide the PR.
Any thoughts on this?
Here is an example of what a custom parser using this could look like:
class MultiPartJsonParser(parsers.MultiPartParser): def parse(self, stream, media_type=None, parser_context=None): result = super().parse( stream, media_type=media_type, parser_context=parser_context ) data = json.loads(result.data['data']) # Use parse_json to parse simple json rather than a request japi_data = parsers.JSONParser.parse_json(data, media_type, parser_context) return parsers.DataAndFiles(japi_data, result.files)
Beta Was this translation helpful? Give feedback.
All reactions
Replies: 1 comment
-
Thanks for bringing up this discussion.
I would be skeptical to include a MultiPartParser in DJA as it is not standardized (yet) how it supposed to work. I am very supportive though to make the public API of DJA as easy extensible as possible so not standardized features can be experimented with in 3rdParty libraries.
Therefore, feel free to open a PR. I would call the method rather parse_data which makes more sense in the JSON:API spec context.
Beta Was this translation helpful? Give feedback.