Skillversitas

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.