Hi everyone,
I want to contribute to this project as a part of GSOC 2023. I have never contributed to any of the official Django projects earlier but I have experience using the framework for last 2 years. In this discussion I would like to propose a high level view of how this can be implemented, any kind of feedback and reference to resources for a more detailed and clear perspective about the project from your side would be very much appreciated, before I start writing the proposal.
Project Title : Configurable Content Type Parsing
Project Description(Given):
For Django 5.0 we’re looking to modernize the HTTPRequest
object, adding a content-type aware request.data
property. This will parse request.body
according to the content type.
The initial phase — targeted for before GSoC — will add request.data
and add support for JSON body handling, but the next phase is to make that fully pluggable with custom parsers.
- Add a list of parsers to the request object, that can be customised — in a middleware for example — at any point prior to accessing
request.data
. - Parsers should implement a
can_handle(content_type) -> Bool
method. The first parser returning True will be selected to parse therequest.body
.
Expected outcome is a PR allowing configurable content type parsing.
High level thoughts on implementation :
Step 1: Add a parsers
list to the HttpRequest
object :
We’ll start by adding a parsers
list to the HttpRequest
object that will contain instances of parser classes. This list will be empty by default, and will be populated by custom parsers added via middleware.
Step 2: Define a Parser
abstract class
We’ll define a Parser
abstract class that all custom parsers must inherit from. This abstract class should define the can_handle(content_type) -> Bool
method that checks whether the parser can handle the given content type.
Step 3: Implement a default JSONParser
class
We’ll implement a default JSONParser
class that inherits from Parser
and handles JSON request bodies. This parser will be added to the parsers
list by default.
Possible high level code example
import json
class JSONParser(Parser):
def can_handle(self, content_type):
return content_type == 'application/json'
def parse(self, body):
return json.loads(body.decode('utf-8'))
Step 4 : Add a data
property to the HttpRequest
object
We’ll add a data
property to the HttpRequest
object that will be responsible for parsing the request body. This property should first check the content type of the request, and then iterate through the parsers
list to find the first parser that can handle the content type. If a parser is found, it should be used to parse the request body, and the parsed data should be returned. If no parser can handle the content type, a UnsupportedMediaType
exception should be raised.
Possible high level code example
from django.http import UnsupportedMediaType
class HttpRequest:
def __init__(self):
.......code........
self.parsers = [JSONParser()]
@property
def data(self):
content_type = self.headers.get('Content-Type', '')
for parser in self.parsers:
if parser.can_handle(content_type):
return parser.parse(self.body)
raise UnsupportedMediaType('Unsupported content type: {}'.format(content_type))
Step 5: Allow customization of the parsers
list via middleware
We’ll allow customization of the parsers
list by providing a way to add or remove parsers. This can be done by adding methods to the middleware that allow adding and removing parsers from the parsers
list.
Possible high level code example
class CustomParserMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
# Add custom parsers here
request.parsers.append(CustomParser())
response = self.get_response(request)
return response
Step 6: Document the changes and add appropriate tests
Finally, we’ll document the changes and add appropriate tests to ensure the new functionality is working as expected. We should test that the default JSONParser
is able to parse JSON request bodies correctly, and that custom parsers added via middleware are able to parse request bodies of their specified content types.
Due to my beginner level understanding of the codebase there is a lot of scope room for improvement. Your suggestions willbe of great help.