Form Data and File Uploads
When you need to receive form fields instead of JSON, use the Form class to define parameters that should be extracted from the application/x-www-form-urlencoded request body.
Receive Form Fields
To use form fields, declare your parameters with Annotated and Form.
from typing import Annotated
from fastapi import FastAPI, Form
app = FastAPI()
@app.post("/login/")
async def login(username: Annotated[str, Form()], password: Annotated[str, Form()]):
return {"username": username}
FastAPI uses the Form class (from fastapi.params) to signal that the data should be read from the form body rather than the query string or a JSON body.
Upload Files
For file uploads, use the File class. You can receive files as bytes or as an UploadFile object.
Small Files as Bytes
If you declare the parameter type as bytes, FastAPI will read the entire file into memory. This is suitable for small files.
from typing import Annotated
from fastapi import FastAPI, File
app = FastAPI()
@app.post("/files/")
async def create_file(file: Annotated[bytes, File()]):
return {"file_size": len(file)}
Large Files with UploadFile
For larger files, use UploadFile (from fastapi.datastructures). It uses a SpooledTemporaryFile, meaning it stays in memory up to a limit and is then stored on disk, preventing your server from running out of RAM.
from fastapi import FastAPI, UploadFile
app = FastAPI()
@app.post("/uploadfile/")
async def create_upload_file(file: UploadFile):
return {
"filename": file.filename,
"content_type": file.content_type,
"size": file.size
}
UploadFile provides several async methods for interacting with the file:
await file.read(size): Reads a number of bytes.await file.seek(offset): Moves to a byte position in the file.await file.write(data): Writes bytes to the file.await file.close(): Closes the file.
Multiple File Uploads
You can receive multiple files at once by declaring a list of bytes or a list of UploadFile.
from typing import Annotated
from fastapi import FastAPI, File, UploadFile
app = FastAPI()
@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]}
Combine Form and File Parameters
You can define both Form and File parameters in the same path operation. When you do this, FastAPI ensures the request is processed as multipart/form-data.
from typing import Annotated
from fastapi import FastAPI, File, Form, UploadFile
app = FastAPI()
@app.post("/files/")
async def create_file(
file: Annotated[bytes, File()],
fileb: Annotated[UploadFile, File()],
token: Annotated[str, Form()],
):
return {
"file_size": len(file),
"token": token,
"fileb_content_type": fileb.content_type,
}
Use Pydantic Models for Forms
To group multiple form fields into a single object, use a Pydantic model and annotate it with Form().
from typing import Annotated
from fastapi import FastAPI, Form
from pydantic import BaseModel
app = FastAPI()
class FormData(BaseModel):
username: str
password: str
@app.post("/login/")
async def login(data: Annotated[FormData, Form()]):
return data
Troubleshooting
Requirement: python-multipart
FastAPI relies on the python-multipart library to parse form data and files. If you encounter errors when trying to read Form or File parameters, ensure it is installed:
pip install python-multipart
Memory Usage
Avoid using bytes for very large files, as this will load the entire file into your server's RAM. Always prefer UploadFile for production applications handling user-uploaded content.
Form vs JSON
You cannot declare a JSON body (using Body) and Form data in the same request. A single HTTP request can only have one body type, and using Form or File forces the media type to application/x-www-form-urlencoded or multipart/form-data.