connexion
connexion copied to clipboard
Error trying to upload file through POST with multipart/mixed
Description
When trying to upload an image file, with a POST using multipart/mixed, I see a TypeError, reported as an internal server error.
Besides fixing this internal server error I am also interested in a work-around to get a connexion to upload a file.
Expected behaviour
Expected behaviour is that the function postMatch_Sessions shall be called.
Actual behaviour
An error in the server while trying to retrieve the information from the body of the POST action.
Steps to reproduce
Using the following files: zz/x.yaml:
openapi: 3.0.0
servers:
- description: is this needed
url: http://localhost:8080/sacei/0.0.1
info:
description: SACEI API
version: 0.0.1
title: SACEI
paths:
/Match_Sessions:
post:
description: start a new session
operationId: sacei.postMatch_Sessions
responses:
'201':
description: item created
requestBody:
content:
multipart/mixed:
schema:
type: object
properties:
ifov:
description: IFOV in radians
type: number
image:
type: string
format: binary
encoding:
image:
contentType: image/png, image/jpeg
sacei.py:
def postMatch_Sessions():
print('postMatch_Sessions')
test.py:
import connexion
a = connexion.App('name', specification_dir='zz/')
a.add_api('x.yaml')
a.run(port=8080)
Run test.py, and running the command (from outside the docker -- translating port 8080 to 11091):
> curl -X 'POST' 'http://localhost:11091/sacei/0.0.1/Match_Sessions' -H 'Content-Type: multipart/mixed' -d '{"ifov":0.1, "image":""}'
this commands returns:
{
"detail": "The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.",
"status": 500,
"title": "Internal Server Error",
"type": "about:blank"
}
and the output of the test.py program is:
* Running on http://172.27.0.2:8080/ (Press CTRL+C to quit)
[2022-02-09 16:02:19,945] ERROR in app: Exception on /sacei/0.0.1/Match_Sessions [POST]
Traceback (most recent call last):
File "/opt/conda/lib/python3.8/site-packages/Flask-2.0.2-py3.8.egg/flask/app.py", line 2073, in wsgi_app
response = self.full_dispatch_request()
File "/opt/conda/lib/python3.8/site-packages/Flask-2.0.2-py3.8.egg/flask/app.py", line 1518, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/opt/conda/lib/python3.8/site-packages/Flask-2.0.2-py3.8.egg/flask/app.py", line 1516, in full_dispatch_request
rv = self.dispatch_request()
File "/opt/conda/lib/python3.8/site-packages/Flask-2.0.2-py3.8.egg/flask/app.py", line 1502, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)
File "/opt/conda/lib/python3.8/site-packages/connexion-2020.0.dev1-py3.8.egg/connexion/decorators/decorator.py", line 68, in wrapper
response = function(request)
File "/opt/conda/lib/python3.8/site-packages/connexion-2020.0.dev1-py3.8.egg/connexion/decorators/uri_parsing.py", line 149, in wrapper
response = function(request)
File "/opt/conda/lib/python3.8/site-packages/connexion-2020.0.dev1-py3.8.egg/connexion/decorators/validation.py", line 193, in wrapper
response = function(request)
File "/opt/conda/lib/python3.8/site-packages/connexion-2020.0.dev1-py3.8.egg/connexion/decorators/parameter.py", line 97, in wrapper
operation.get_arguments(request.path_params, query, request_body,
File "/opt/conda/lib/python3.8/site-packages/connexion-2020.0.dev1-py3.8.egg/connexion/operations/abstract.py", line 284, in get_arguments
ret.update(self._get_body_argument(body, arguments,
File "/opt/conda/lib/python3.8/site-packages/connexion-2020.0.dev1-py3.8.egg/connexion/operations/openapi.py", line 296, in _get_body_argument
body_arg.update(body or {})
TypeError: cannot convert dictionary update sequence element #0 to a sequence
172.27.0.1 - - [09/Feb/2022 16:02:19] "POST /sacei/0.0.1/Match_Sessions HTTP/1.1" 500 -
Additional info:
Output of the commands:
python --version: 3.8.8pip show connexion | grep "^Version\:": Version: 2020.0.dev1 (== today's github version) (similar error message when using version 2.6.0)
@KlamerS , the 2.12.0 release that came out today contains some recent fixes to multipart/mixed bodies for aiohttp. However, I see you're using flask and this issue may be a duplicate report of #992
multipart/mixed is not supported by either Flask/werkzeug or starlette, which connexion is built on. You can either use multipart/form-data, or parse the multipart/mixed yourself by reading the stream on the request object yourself.
Since it is apparently part of the openapi spec, to be spec compliant, isn't it therefore incumbent on connexion to do as you suggest and parse the stream itself?
In theory it would be great to support it. But multipart/mixed is so complex and support across the Python ecosystem lacking that it's not feasible.