File Upload | 🍓 Strawberry GraphQL
All Strawberry integrations support multipart uploads as described in the
GraphQL multipart request specification.
This includes support for uploading single files as well as lists of files.
Uploads can be used in mutations via the Upload
scalar.
The type passed at runtime depends on the integration:
Since these integrations use asyncio for communication, the resolver must be async.
Additionally, these servers rely on the python-multipart
package, which is not included by Strawberry by default. It can be installed directly, or, for convenience, it is included in extras: strawberry[asgi]
(for ASGI/Starlette) or strawberry[fastapi]
(for FastAPI). For example:
- if using Pip,
pip install 'strawberry[fastapi]'
- if using Poetry,
strawberry = { version = "...", extras = ["fastapi"] }
inpyproject.toml
.
Example:
import
typingimport
strawberryfrom
strawberry.
file_uploads import
Upload
@strawberry
.
inputclass
FolderInput
:
files
:
typing.
List[
Upload]
@strawberry
.
typeclass
Mutation
:
@strawberry
.
mutation
async
def
read_file
(
self,
file
:
Upload)
-
>
str
:
return
(
await
file
.
read(
)
)
.
decode(
"utf-8"
)
@strawberry
.
mutation
async
def
read_files
(
self,
files:
typing.
List[
Upload]
)
-
>
typing.
List[
str
]
:
contents
=
[
]
for
file
in
files:
content
=
(
await
file
.
read(
)
)
.
decode(
"utf-8"
)
contents
.
append(
content)
return
contents
@strawberry
.
mutation
async
def
read_folder
(
self,
folder:
FolderInput)
-
>
typing.
List[
str
]
:
contents
=
[
]
for
file
in
folder.
files:
content
=
(
await
file
.
read(
)
)
.
decode(
"utf-8"
)
contents
.
append(
content)
return
contents
Example:
import
typingimport
strawberryfrom
strawberry.
file_uploads import
Upload
@strawberry
.
inputclass
FolderInput
:
files
:
typing.
List[
Upload]
@strawberry
.
typeclass
Mutation
:
@strawberry
.
mutation
def
read_file
(
self,
file
:
Upload)
-
>
str
:
return
file
.
read(
)
.
decode(
"utf-8"
)
@strawberry
.
mutation
def
read_files
(
self,
files:
typing.
List[
Upload]
)
-
>
typing.
List[
str
]
:
contents
=
[
]
for
file
in
files:
content
=
file
.
read(
)
.
decode(
"utf-8"
)
contents
.
append(
content)
return
contents
@strawberry
.
mutation
def
read_folder
(
self,
folder:
FolderInput)
-
>
typing.
List[
str
]
:
contents
=
[
]
for
file
in
folder.
files:
contents
.
append(
file
.
read(
)
.
decode(
"utf-8"
)
)
return
contents
The tricky part is sending the HTTP request from the client because it must follow the GraphQL multipart request specifications mentioned above.
The multipart/form-data
POST request’s data must include:
operations
key for GraphQL request with query and variablesmap
key with mapping some multipart-data to exact GraphQL variable- and other keys for multipart-data which contains binary data of files
Assuming you have your schema up and running, here there are some requests examples:
curl
localhost:8000/graphql \
-F
operations
=
'{ "query": "mutation($file: Upload!){ readFile(file: $file) }", "variables": { "file": null } }'
\
-F
map
=
'{ "file": ["variables.file"] }'
\
-F
file
=
@a.txt
curl
localhost:8000/graphql \
-F
operations
=
'{ "query": "mutation($files: [Upload!]!) { readFiles(files: $files) }", "variables": { "files": [null, null] } }'
\
-F
map
=
'{"file1": ["variables.files.0"], "file2": ["variables.files.1"]}'
\
-F
file1
=
@b.txt \
-F
file2
=
@c.txt
curl
localhost:8000/graphql \
-F
operations
=
'{ "query": "mutation($folder: FolderInput!) { readFolder(folder: $folder) }", "variables": {"folder": {"files": [null, null]}} }'
\
-F
map
=
'{"file1": ["variables.folder.files.0"], "file2": ["variables.folder.files.1"]}'
\
-F
file1
=
@b.txt \
-F
file2
=
@c.txt
Mục lục bài viết
Was this helpful? What can we improve?
😭
😕
😃
🤩
Edit on Github