FastAPI: Handling Form Data, Not Just JSON
FastAPI can handle classic HTML form data, not just JSON. Use `Form` to define expected fields in your endpoint, just like query parameters. It's ideal for login pages. The footgun: forgetting to `pip install python-multipart` will break form parsing.
WHY IT EXISTS Web applications existed long before JSON APIs became standard. Many systems, especially simple HTML pages, still submit data using standard HTML forms. FastAPI needs a way to receive this application/x-www-form-urlencoded data, not just application/json.
THE MENTAL MODEL Think of Form as a data source declaration, just like Query, Path, or Body. You're telling FastAPI, "Expect this piece of data to come from a submitted form field, not from the URL path or a JSON payload." It lets you use the same powerful type-hinting and validation system for form data.
HOW IT WORKS First, you must pip install python-multipart. In your path operation function, you import Form from fastapi. Then, you declare a parameter with a type hint and use Form() as the default value (e.g., username: str = Form()). FastAPI will then automatically parse the incoming request body as form data and map the fields to your function parameters. The modern, recommended syntax uses Annotated from Python's typing module (e.g., username: Annotated[str, Form()]).
WHEN TO USE IT Use Form when you are building an endpoint that will be called by a standard HTML form submission. This is common for login pages, contact forms, or any simple data submission from a non-JavaScript-heavy frontend. It's also used when integrating with OAuth2 flows that require form data.
WHEN NOT TO USE IT Do not use Form if your client is sending a JSON payload. For that, you should use Pydantic models and let FastAPI parse the request body as JSON. You cannot declare a parameter to receive both form data and a JSON body in the same request, as they both read from the request body.
ONE CANONICAL EXAMPLE A simple login endpoint demonstrates this perfectly. from fastapi import FastAPI, Form from typing import Annotated app = FastAPI() @app.post("/login/") async def login(username: Annotated[str, Form()], password: Annotated[str, Form()]): return {"username": username} In this example, a POST request to /login/ with form fields username and password will be correctly processed.
Read the original → fastapi.tiangolo.com
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.