I am trying to send a "multipart/form-data" request through aiohttp. I have already tried using requests and the request works fine.
I have a class where self.files
is an io.BytesIO
object and self.data
is a dictionary of string values.
Here's the relevant part of my code in this class:
params = {
"url": self.url,
"headers": self.headers,
"timeout": self.timeout,
"proxy": self.proxy
}
# No data is allowed in the body for GET requests
if self.method != "get":
if self.header_content_type == "multipart/form-data":
with aiohttp.MultipartWriter("form-data") as mp:
if self.data:
for key, value in self.data.items():
part = mp.append(value, {'content-type': 'form-data'})
part.set_content_disposition('form-data', name=key)
if self.files:
for key, value in self.files.items():
part = mp.append(value.read(), {'content-type': 'form-data'})
part.set_content_disposition('form-data', name=key)
params["data"] = mp
async with aiohttp.ClientSession(trust_env=False) as session:
async with session.post(**params) as response:
print(params)
return response
However, this fails with a 422 error from the called API which means that the data is not properly formed.
The output of the params that I have printed above is follows:
{'url': 'http://localhost:9999/v2/toing', 'headers': {'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkY200Y2hlZSIsImV4cCI6MTcxODI4MzAyMX0.6d5XcxucVLvml4O0Z-JBfOvrJLtz254371aQ0XKiCuI'}, 'timeout': 500, 'proxy': None, 'data': <aiohttp.multipart.MultipartWriter object at 0x1149aff40>}
It seems that the "data" section is not properly formatted and that the files attribute is missing.
Here are the parameters that work for me using requests.post:
('http://localhost:9999/v2/toing', {'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkY200Y2hlZSIsImV4cCI6MTcxODMwMjQyMH0.lpAfQKISeIhUIcSf1OdM9ZN3eOUB0YHwcfVshY7y0VQ'}) {'data': {'request_data': '{"kk_shape": [2595, 2826], "algorithm_type": "trauma", "age": "33", "center": "toing", "is_spx": false, "detected_xx": "yyy", "kk": "hand"}'}, 'files': {'image_arr': <_io.BytesIO object at 0x116faed90>}, 'header_content_type': 'multipart/form-data'}
Is it possible to send files
and data
separately using aiohttp as it seems aiohttp.ClientSession.session.post
does not have a files
parameter as in requests.post?
What am I doing wrong?
This is indeed possibleby using aiohttp.FormData
instead of aiohttp.MultipartWriter
.
Here's a working modification of the code:
params = {
"method": self.method,
"url": self.url,
"headers": self.headers,
"timeout": self.timeout,
"proxy": self.proxy
}
# No data is allowed in the body for GET requests
if self.method != "get":
form_data = aiohttp.FormData()
if self.header_content_type == "multipart/form-data":
if self.data:
for key, value in self.data.items():
form_data.add_field(name=key, value=value)
if self.files:
for key, value in self.files.items():
form_data.add_field(name=key, value=value)
params["data"] = form_data
else:
params["data"] = self.data
async with aiohttp.ClientSession(trust_env=False) as session:
async with session.request(**params) as response:
print(params)
return response