Accessing Form Data
HTML forms and some clients submit data as form-encoded bodies (application/x-www-form-urlencoded) or multipart. Plain type-hinted parameters are interpreted as query parameters, so FastAPI provides the Form dependency to read form fields explicitly.
Basic Form Data
from fastapi import FastAPI, Form
app = FastAPI()
@app.post("/login/")
def login(username: str = Form(), password: str = Form()):
return {"username": username}
Test it with curl:
curl -X POST http://127.0.0.1:8000/login/ \
-d "username=ada&password=s3cret"
Required and Optional Fields
Form fields without defaults are required; give a default (or a | None type) to make them optional. Constraints work the same way as everywhere:
from typing import Annotated
from pydantic import Field
@app.post("/subscribe/")
def subscribe(
email: str = Form(),
plan: Annotated[str, Field(pattern=r"^(free|pro)$")] = Form("free"),
):
return {"email": email, "plan": plan}
Combining Form with Body and Query
@app.post("/items/{item_id}")
def update_item(
item_id: int,
name: str = Form(),
limit: int = 10,
):
return {"item_id": item_id, "name": name, "limit": limit}
HTML Forms
Render a form that posts to your endpoint:
<form action="/login/" method="post">
<input name="username" required />
<input name="password" type="password" required />
<button>Sign in</button>
</form>
Remember: you cannot use plain JSON body models and Form fields in the same endpoint - the body can be either JSON or form data, not both.
Summary
Use Form() parameters to read application/x-www-form-urlencoded submissions, with the same required/optional and constraint rules as other parameters. Pair them with plain HTML forms or curl -d, and keep in mind that form data replaces the JSON body for that endpoint.