swagger-api / swagger-api/swagger-codegen
[typescript-angular] multipart/form-data submissions include filename="blob" which confuses backends
Nobody has claimed this yet.
- Dominant language
- Mustache
- Stars
- 17.8k
- Forks
- 6k
- PR merge metrics
- No merged PRs in 30d
Description
Description
I am having an issue with the typescript-angular generated code. I have an openapi spec which uses a multipart/form-data request that includes both a file and a json document field.
The multipart body in the request, when submitted by chrome, tends to look like this:
POST /api/1.0/item/add HTTP/1.1
...
content-type: multipart/form-data; boundary=----WebKitFormBoundaryOsISlkzGT7TAuz5W
------WebKitFormBoundaryOsISlkzGT7TAuz5W
Content-Disposition: form-data; name="media"; filename="foo.wav"
Content-Type: audio/wav
RIFF...
...
------WebKitFormBoundaryWC8tMAERR4StMjHj
Content-Disposition: form-data; name="info"; filename="blob"
Content-Type: application/json
{"type":"audio","tags":["green","red"], ... }
------WebKitFormBoundaryWC8tMAERR4StMjHj--
The issue is that the json document (info), which was not from an <input type='file'...>, contains a filename="blob" value. When a backend receives this, it cannot tell the difference between an entity is should write to a temp file before calling the handler (a typical behavior) or just a string field which has a given a content type.
I'm using python's aiohttp to receive the request, and since filename has a value, it's returning this as a aiohttp.web.FileField(). I tracked that down to here: https://github.com/aio-libs/aiohttp/blob/master/aiohttp/web_request.py#L621
I didn't test it, but I believe a Flask backed would treat it the same way: https://github.com/pallets/werkzeug/blob/master/src/werkzeug/formparser.py#L467
This happens because the generated typescript-angular service eventually does this...
formParams = new FormData();
...
formParams = formParams.append('info', useForm ? new Blob([JSON.stringify(info)], { type: 'application/json' }) : info) || formParams;
... when building the request. This seems basically correct. The docs for FormData.append() says that if a Blob() is passed, this the default filename will be "blob" (as I'm observing) but can vary from browser to browser. See https://developer.mozilla.org/en-US/docs/Web/API/FormData/append
However, if I pass "" as the 3rd optional parameter for a filename, then the request body still contains filename="", but the backends then treat them as non-files, and everything works from there on out.
I didn't find all this out until I started using the browser. My unit tests, using curl -F "{json};type=application/json" didn't feel the need to include a filename component in the content-disposition field.
Swagger-codegen version
Version 2.4.10 (probably not a regresssion)
Suggest a fix/enhancement
I was going to suggest adding "" when calling append() for blobs. I can make a PR, but do we think it would be accepted? Is existing code expecting a value of blob or whatever unpredictable value it may have depending on the browser?
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at the typescript-angular service generation path that builds FormData and the FormData.append('info', ...) entry point shown in the report. Review the existing unit coverage, noting that the reported curl-based test does not include a filename component. Done means JSON Blob parts are submitted without a misleading default filename and regression coverage verifies the multipart behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- angular, typescript
- Domain
- api
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100