I'm using a custom parser on my POST endpoint so that I can support file uploads and nested objects in the same endpoint (context):
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)
return parsers.DataAndFiles(json.loads(result.data["data"]), result.files)
Data is posted as multipart/form-data with a single "data" key containing the full form as a json string, for example:
data: "{\"about\": {\"name\": \"a\"}}"
My serializer is defined like so:
def AboutSerializer(serializers.Serializer):
name = serializers.CharField()
def FooSerializer(serializers.Serializer):
about = AboutSerializer()
# more fields
My drf_spectacular schema shows this endpoint expects an "about" field, but actually the POST request body should be a "data" field containing a JSON string with the "about" field inside of it.
Is there any way to make drf_spectqacular aware of my custom parser, so that the schema reflects that the only key in the form body should be data, and that data should be a JSON-encoded version of my FooSerializer?
I've realized this can't be done in drf_spectacular. However, depending on which schema/api tools you use on the frontend, you may be able to convert to the desired format there. I'm using openapi-fetch for type-aware fetching in typescript, and was able to achieve this with the following bodySerializer:
export function multipartJsonBodySerializer(body: Record<string, unknown>) {
const formData = new FormData();
const jsonData: Record<string, unknown> = {};
for (const [key, value] of Object.entries(body)) {
if (value instanceof File) {
formData.append(key, value);
} else {
jsonData[key] = value;
}
}
formData.append("data", JSON.stringify(jsonData));
return formData;
}
// Example post:
const body = {"about": {"name": "a"}}
POST("/api/endpoint/", {
body: body,
bodySerializer: multipartJsonBodySerializer,
})
The body object is type-checked as usual then it's converted to my custom format by the bodySerializer
, before being posted.