Guide Home Part 1 - FastAPI Foundations Part 2 - Building Applications Part 3 - Pages and HTML Part 4 - Security and Deployment Part 5 - Going Further Capstone Build Plan Markdown Source All Guides

Chapter 16: Binding and Validating Forms

HTML forms are not JSON. FastAPI can bind form fields, but it is more manual than Pydantic JSON bodies.

from typing import Annotated

from fastapi import Form
from pydantic import BaseModel, Field, ValidationError


class RecipeForm(BaseModel):
    title: str = Field(min_length=1, max_length=120)
    instructions: str = Field(min_length=1)
    servings: int = Field(ge=1, le=50)


@router.post("/recipes/new")
def create_recipe_from_form(
    request: Request,
    title: Annotated[str, Form()],
    instructions: Annotated[str, Form()],
    servings: Annotated[int, Form()],
):
    try:
        form = RecipeForm(
            title=title,
            instructions=instructions,
            servings=servings,
        )
    except ValidationError as error:
        return templates.TemplateResponse(
            "recipes/new.html",
            {"request": request, "errors": error.errors()},
            status_code=400,
        )
    ...

For heavy form workflows, Django becomes attractive because forms, model forms, CSRF, sessions, auth, and admin are integrated. In FastAPI, you can still build excellent form flows, but you own more of the conventions.