GraphQL multipart uploads do not contain mimetype
aalmazan opened this issue · 3 comments
Describe the bug
Currently on v3.4.0
when uploading files, a mimetype is not being provided. This seems to default files as text/plain
, at least on the Apollo GraphQL server implementation I've testing against.
The transport I'm currently using is requests
, however, it's probably the case on other transports as well:
https://github.com/graphql-python/gql/blob/master/gql/transport/requests.py#L185-L187
https://github.com/graphql-python/gql/blob/master/gql/transport/aiohttp.py#L276-L278
Changing the following will work for my use case (requests
transport):
# original
fields[k] = (getattr(v, "name", k), v)
# new
fields[k] = (getattr(v, "name", k), v, 'application/pdf')
# or
fields[k] = (getattr(v, "name", k), v, USER_PROVIDED_MIMETYPE)
To Reproduce
Same as above
Expected behavior
I suspect there's two ways about this:
- Autodetect the file's mimetype (or have an argument somewhere that allows the user to opt-in to this behavior):
import mimetypes
mimetype, _ = mimetypes.guess_type(file.name)
- Allow the user to provide the mimetype manually:
# Taken from the docs on uploading files: https://gql.readthedocs.io/en/stable/usage/file_upload.html
# Single file upload
with open("YOUR_FILE_PATH", "rb") as f:
# old
# params = {"file": f}
# new
params = {"file": (f, USER_DEFINED_MIMETYPE)}
result = client.execute(
query, variable_values=params, upload_files=True
)
# Multi-file upload
f1 = open("YOUR_FILE_PATH_1", "rb")
f2 = open("YOUR_FILE_PATH_2", "rb")
params = {"files": [(f1, USER_DEFINED_MIMETYPE_1), (f2, USER_DEFINED_MIMETYPE_2)]}
System info (please complete the following information):
- OS: Ubuntu
- Python version: 3.9.12
- gql version: 3.4.0
- graphql-core version:
Option 1. could be done.
Option 2. should be done another way as we are detecting the files by checking their type, and now the provided value is a tuple instead of a File object.
One way to do it would be to add a new parameter to the file object and use it if it is present.
Something like this:
with open("YOUR_FILE_PATH", "rb") as f:
f.content_type = "application/pdf";
params = {"file": f}
result = client.execute(
query, variable_values=params, upload_files=True
)
Please check the PR #386
Only the option 2 has been retained.
Detecting the content-type depending on the filename can be done by the user if needed.
@leszekhanusz Thanks for the quick PR! I created a fork that had very similar changes as well (but just for requests) and it all works well for me.