Chapter 3 · Path Parameters and Query Parameters
Chapter goals: Master path parameter type conversion and validation, declare optional/required/list query parameters, and understand FastAPI's recognition rules and common pitfalls when mixing both.
3.1 Path Parameters and Auto Type Conversion
Parts of the path wrapped in {} are path parameters. FastAPI parses and validates them based on the function signature's type annotations:
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/{item_id}")
def read_item(item_id: int):
# Annotated as int: request to /items/5 auto-converts;
# request to /items/abc returns a 422 validation error and never enters the function
return {"item_id": item_id}A request to /items/abc returns a structured error (HTTP 422):
{
"detail": [
{
"type": "int_parsing",
"loc": ["path", "item_id"],
"msg": "Input should be a valid integer, unable to parse string as an integer"
}
]
}This is "types are validation": every type annotation you write is simultaneously a runtime guard and a documentation statement.
3.2 Constraining Values with Enum
To restrict a path parameter to a fixed set of values, use an Enum:
from enum import Enum
from fastapi import FastAPI
app = FastAPI()
class ModelName(str, Enum):
# Inherit from str so members participate in string comparison and serialization
alexnet = "alexnet"
resnet = "resnet"
lenet = "lenet"
@app.get("/models/{model_name}")
def get_model(model_name: ModelName):
if model_name is ModelName.alexnet:
return {"model": model_name, "message": "Deep Learning FTW!"}
return {"model": model_name, "message": "Have some residuals"}Visiting /models/resnet works normally; /models/gpt4 returns 422 with the valid values listed in the error. The docs page renders it as a dropdown.
3.3 Declaration Order Pitfall (Review and Reinforce)
Chapter 2 covered route matching order; here we look at it from the parameter perspective:
from fastapi import FastAPI
app = FastAPI()
# ✅ Static path first
@app.get("/files/latest")
def latest_file():
return {"file": "report-2026.pdf"}
@app.get("/files/{file_path:path}")
def read_file(file_path: str):
# :path converter allows the parameter to include slashes, matching multi-level paths
return {"file_path": file_path}The :path converter is a Starlette feature — /files/a/b/c.txt gives file_path="a/b/c.txt", while a plain str parameter would 404 on slashes. Even so, /files/latest must still be declared first, or it is never reached.
3.4 Query Parameters
Anything after ?key=value&... in the URL is a query parameter. Any scalar parameter in the function signature that is not a path parameter is automatically treated as a query parameter:
from typing import Annotated
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/")
def read_items(
skip: int = 0, # Has default → optional query param, defaults to 0
limit: int = 10,
q: str | None = None, # Optional string, can be None
):
# GET /items/?skip=20&limit=5&q=apple
return {"skip": skip, "limit": limit, "q": q}
@app.get("/search")
def strict_search(keyword: str):
# No default → required query param; missing it returns 422
return {"keyword": keyword}Three rules to remember:
- Parameter name appears in the path template → path parameter;
- Parameter is a scalar type (int/str/bool/float, etc.) → query parameter;
- Parameter is a Pydantic model → request body (Chapter 4).
3.5 Chapter Summary
- Path parameters: type annotation drives auto-conversion and validation; wrong type → 422;
- Enum path params render as dropdowns in /docs;
- Static paths must be declared before parameterized ones;
- Query params: scalar with default = optional; scalar without default = required;
- Pydantic model parameter = request body (next chapter).
🧪 随堂测验
点击你认为正确的选项。答错时会展示正确答案与原因解析。
1. What HTTP status code does FastAPI return when a path parameter fails type validation?
2. How do you make a query parameter optional?
3. Why must /files/latest be declared before /files/{file_path:path}?
4. What determines whether a function parameter is treated as a path param, query param, or body?
🛠️ Hands-On Exercises
- Write a route
GET /products/{product_id}whereproduct_idis validated as an integer greater than 0; test with both valid and invalid IDs. - Add query params
skip(default 0),limit(default 10), and an optionalcategory: str | None = None; test with various combinations. - Create an Enum
Status(str, Enum)with valuesactive/inactive/archived; use it as a path param and verify the /docs dropdown renders all three options.
Proceed to Chapter 4: Request Body and Pydantic Models.