Parameters¶
FastAPI reads path, query and header parameters from the function signature, converts them to the declared
types and validates them (Query(), Path(), Header() constraints and aliases). The binary does the same,
with FastAPI's 422 error bodies.
The example's router, docs_src/tutorial/parameters.py, uses path parameters (an int, a str
enum), query parameters with defaults, constraints and an alias, and header parameters (a list of values for
a repeated header). Like every example on this site, it is compiled and compared with FastAPI in CI (how).
from datetime import date
from enum import Enum
from typing import Annotated
from uuid import UUID
from fastapi import APIRouter, Header, Path, Query
router = APIRouter(prefix="/parameters", tags=["parameters"])
class Shelf(str, Enum):
to_read = "to-read"
reading = "reading"
done = "done"
@router.get("/items/{item_id}")
async def read_item(item_id: int, q: str | None = None, short: bool = False):
item = {"item_id": item_id}
if q:
item["q"] = q
if not short:
item["description"] = "A long description of the item."
return item
@router.get("/shelves/{shelf}")
async def read_shelf(shelf: Shelf):
if shelf is Shelf.done:
return {"shelf": shelf, "message": "Finished books"}
return {"shelf": shelf, "message": f"Books on the {shelf.value} shelf"}
@router.get("/search")
async def search(
q: Annotated[str, Query(min_length=2, max_length=50, pattern="^[a-z ]+$")],
tags: Annotated[list[str], Query(alias="tag")] = [],
limit: Annotated[int, Query(ge=1, le=100)] = 10,
since: date | None = None,
):
return {"q": q, "tags": tags, "limit": limit, "since": since}
@router.get("/files/{file_id}")
async def read_file(
file_id: Annotated[UUID, Path(title="The file's id")],
user_agent: Annotated[str | None, Header()] = None,
x_token: Annotated[list[str], Header()] = [],
):
return {"file_id": file_id, "user_agent": user_agent, "x_token": x_token}
Every route of this file is native: py2axum check docs_src --root . lists them as native, and a bad value
gets FastAPI's 422, loc, msg and input included.
What is native¶
- Path, query, header and cookie parameters (
int/str/bool/float/Enum/UUID/datetime/bytes,X | None, lists — a list header parameter takes every occurrence of the header, likeheaders.getlist—,Query/Path/Header/Cookie(...)constraints and aliases, andAnnotatedconstraints fromannotated_typesorStringConstraints). Errors are FastAPI's 422 bodies, byte for byte. Cookie()parameters readrequest.cookies(Starlette's lenient parser, firstCookieheader, last value wins), under the parameter's name oralias, after the path, query and header parameters as FastAPI does (loc["cookie", name]).- Models of parameters (
Annotated[Model, Query()],Header(),Cookie()), as FastAPI'srequest_params_to_args: each field read under its alias (a header's underscores turned into hyphens unlessHeader(convert_underscores=False); a list field gets every value; an absent field its default when it has one), every other received key added (one value, or the list of them), then the dict validated as the model at["query"],["header"]or["cookie"](extra="forbid"then rejects unknown keys). datetime.timeanddatetime.timedeltaread from strings and numbers as Pydantic does (speedate, python mode):HH:MM[:SS[.ffffff]]times; ISO 8601 durations (P1Y2M3W4DT5H6M7.5S, a year is 365 days and a month 30),[D day[s][,] ]H:MM[:SS[.f]],D d, numbers (and booleans) as seconds; thetime_parsingandtime_delta_parsingmessages. Durations are serialised in JSON as Pydantic's ISO 8601 (PT5M,P1Y38D,-PT1S), and as seconds throughjsonable_encoder.- Timestamps as Pydantic reads them (speedate): numbers and integer strings within years 0000-9999, milliseconds above 2e10.
UUID parameters follow the rules of UUID fields; the decoded path is used for
routing, as in Starlette (Bigger applications).
- An unannotated parameter (def read_item(item_id)) is Any, as in FastAPI: the raw string from the path or
the query (the last value of a repeated query parameter). Constraints (Query(max_length=...)) without an
annotation are refused.
What stays in Python¶
- Refused at compile time: a model of parameters next to another parameter of the same source, in a route with
dependencies (FastAPI merges the dependencies' parameters, which changes how the model is read), in a
dependency, or with a default; an
Annotatedmetadata that changes validation or serialisation (AfterValidator,BeforeValidator,WrapSerializer,Discriminator, a class with__get_pydantic_core_schema__...).
Differences¶
- Known difference: a timezone-aware
time(aZor±HH:MMsuffix, or a number of seconds, which Pydantic reads as UTC) is a 500 (TypeError): the runtime's times are naive. - Known difference: a numeric string with a fraction or an exponent above 2e10 seconds
(
"6.958e+16","253402300800000.0") is read by speedate's float-string path with its own scaling; the binary applies the number's rules (an error past 9999).