Request Files
You can define files to be uploaded by the client using File.
Import File
Section titled “Import File”Import File and UploadFile from fastapi:
from typing import Annotated
from fastapi import FastAPI, File, UploadFile
app = FastAPI()
@app.post("/files/")
async def create_file(file: Annotated[bytes, File()]):
return {"file_size": len(file)}
@app.post("/uploadfile/")
async def create_upload_file(file: UploadFile):
return {"filename": file.filename}Define File Parameters
Section titled “Define File Parameters”Create file parameters the same way you would for Body or Form:
from typing import Annotated
from fastapi import FastAPI, File, UploadFile
app = FastAPI()
@app.post("/files/")
async def create_file(file: Annotated[bytes, File()]):
return {"file_size": len(file)}
@app.post("/uploadfile/")
async def create_upload_file(file: UploadFile):
return {"filename": file.filename}The files will be uploaded as "form data".
If you declare the type of your path operation function parameter as bytes, FastAPI will read the file for you and you will receive the contents as bytes.
Keep in mind that this means that the whole contents will be stored in memory. This will work well for small files.
But there are several cases in which you might benefit from using UploadFile.
File Parameters with UploadFile
Section titled “File Parameters with UploadFile”Define a file parameter with a type of UploadFile:
from typing import Annotated
from fastapi import FastAPI, File, UploadFile
app = FastAPI()
@app.post("/files/")
async def create_file(file: Annotated[bytes, File()]):
return {"file_size": len(file)}
@app.post("/uploadfile/")
async def create_upload_file(file: UploadFile):
return {"filename": file.filename}Using UploadFile has several advantages over bytes:
- You don't have to use
File()in the default value of the parameter. - It uses a "spooled" file:
- A file stored in memory up to a maximum size limit, and after passing this limit it will be stored on disk.
- This means that it will work well for large files like images, videos, large binaries, etc. without consuming all the memory.
- You can get metadata from the uploaded file.
- It has a file-like
asyncinterface. - It exposes an actual Python
SpooledTemporaryFileobject that you can pass directly to other libraries that expect a file-like object.
UploadFile
Section titled “UploadFile”UploadFile has the following attributes:
filename: Astrwith the original file name that was uploaded (e.g.myimage.jpg).content_type: Astrwith the content type (MIME type / media type) (e.g.image/jpeg).file: ASpooledTemporaryFile(a file-like object). This is the actual Python file object that you can pass directly to other functions or libraries that expect a "file-like" object.
UploadFile has the following async methods. They all call the corresponding file methods underneath (using the internal SpooledTemporaryFile).
write(data): Writesdata(strorbytes) to the file.read(size): Readssize(int) bytes/characters of the file.seek(offset): Goes to the byte positionoffset(int) in the file.- E.g.,
await myfile.seek(0)would go to the start of the file. - This is especially useful if you run
await myfile.read()once and then need to read the contents again.
- E.g.,
close(): Closes the file.
As all these methods are async methods, you need to "await" them.
For example, inside of an async path operation function you can get the contents with:
contents = await myfile.read()If you are inside of a normal def path operation function, you can access the UploadFile.file directly, for example:
contents = myfile.file.read()What is "Form Data"
Section titled “What is "Form Data"”The way HTML forms (<form></form>) send the data to the server normally uses a "special" encoding for that data, it's different from JSON.
FastAPI will make sure to read that data from the right place instead of JSON.
Optional File Upload
Section titled “Optional File Upload”You can make a file optional by using standard type annotations and setting a default value of None:
from typing import Annotated
from fastapi import FastAPI, File, UploadFile
app = FastAPI()
@app.post("/files/")
async def create_file(file: Annotated[bytes | None, File()] = None):
if not file:
return {"message": "No file sent"}
else:
return {"file_size": len(file)}
@app.post("/uploadfile/")
async def create_upload_file(file: UploadFile | None = None):
if not file:
return {"message": "No upload file sent"}
else:
return {"filename": file.filename}UploadFile with Additional Metadata
Section titled “UploadFile with Additional Metadata”You can also use File() with UploadFile, for example, to set additional metadata:
from typing import Annotated
from fastapi import FastAPI, File, UploadFile
app = FastAPI()
@app.post("/files/")
async def create_file(file: Annotated[bytes, File(description="A file read as bytes")]):
return {"file_size": len(file)}
@app.post("/uploadfile/")
async def create_upload_file(
file: Annotated[UploadFile, File(description="A file read as UploadFile")],
):
return {"filename": file.filename}Multiple File Uploads
Section titled “Multiple File Uploads”It's possible to upload several files at the same time.
They would be associated to the same "form field" sent using "form data".
To use that, declare a list of bytes or UploadFile:
from typing import Annotated
from fastapi import FastAPI, File, UploadFile
from fastapi.responses import HTMLResponse
app = FastAPI()
@app.post("/files/")
async def create_files(files: Annotated[list[bytes], File()]):
return {"file_sizes": [len(file) for file in files]}
@app.post("/uploadfiles/")
async def create_upload_files(files: list[UploadFile]):
return {"filenames": [file.filename for file in files]}
@app.get("/")
async def main():
content = """
<body>
<form action="/files/" enctype="multipart/form-data" method="post">
<input name="files" type="file" multiple>
<input type="submit">
</form>
<form action="/uploadfiles/" enctype="multipart/form-data" method="post">
<input name="files" type="file" multiple>
<input type="submit">
</form>
</body>
"""
return HTMLResponse(content=content)You will receive, as declared, a list of bytes or UploadFiles.
Multiple File Uploads with Additional Metadata
Section titled “Multiple File Uploads with Additional Metadata”And the same way as before, you can use File() to set additional parameters, even for UploadFile:
from typing import Annotated
from fastapi import FastAPI, File, UploadFile
from fastapi.responses import HTMLResponse
app = FastAPI()
@app.post("/files/")
async def create_files(
files: Annotated[list[bytes], File(description="Multiple files as bytes")],
):
return {"file_sizes": [len(file) for file in files]}
@app.post("/uploadfiles/")
async def create_upload_files(
files: Annotated[
list[UploadFile], File(description="Multiple files as UploadFile")
],
):
return {"filenames": [file.filename for file in files]}
@app.get("/")
async def main():
content = """
<body>
<form action="/files/" enctype="multipart/form-data" method="post">
<input name="files" type="file" multiple>
<input type="submit">
</form>
<form action="/uploadfiles/" enctype="multipart/form-data" method="post">
<input name="files" type="file" multiple>
<input type="submit">
</form>
</body>
"""
return HTMLResponse(content=content)Use File, bytes, and UploadFile to declare files to be uploaded in the request, sent as form data.