Query Parameter Models
Group related query parameters into a Pydantic model for cleaner code and better organization.
🎯 What You'll Learn
- •Group query parameters into Pydantic models
- •Use model_config with extra='forbid' to reject unexpected parameters
- •Understand the benefits of parameter models over individual parameters
- •Apply validation to groups of query parameters
Query Parameter Models
What You'll Learn
When your API endpoints accept many query parameters, listing them all individually in the function signature becomes messy and hard to maintain. FastAPI 0.115+ introduces query parameter models, letting you group related query parameters into a single Pydantic model.
By the end of this lesson, you'll understand how to:
- Group query parameters into Pydantic models
- Use
model_configwithextra="forbid"to reject unexpected parameters - Understand the benefits of parameter models over individual parameters
- Apply validation to groups of query parameters
The Problem: Too Many Parameters
Consider an endpoint with many query parameters:
@app.get("/items/")
def list_items(
limit: int = 10,
offset: int = 0,
order_by: str = "created_at",
search: str | None = None,
category: str | None = None,
min_price: float | None = None,
max_price: float | None = None,
):
...
This is hard to read, hard to reuse, and hard to maintain. If another endpoint needs the same filters, you have to copy all the parameters again.
The Solution: Query Parameter Models
With FastAPI 0.115+, you can group query parameters into a Pydantic model:
from fastapi import FastAPI, Query
from pydantic import BaseModel
app = FastAPI()
class FilterParams(BaseModel):
model_config = {"extra": "forbid"}
limit: int = 10
offset: int = 0
order_by: str = "created_at"
@app.get("/items/")
def list_items(filter_query: FilterParams = Query()):
return {"filters": filter_query.model_dump()}
The key pieces:
- Define a Pydantic model with your query parameters as fields
- Annotate the parameter with
Query()so FastAPI knows to extract values from the query string - Use
model_config = {"extra": "forbid"}to reject any unknown query parameters
Key Concepts
The Query() Annotation
When you declare a Pydantic model parameter in an endpoint, FastAPI normally assumes it is a JSON body. The Query() annotation tells FastAPI: "Read these fields from the query string instead."
# Without Query() - FastAPI expects a JSON body
def endpoint(params: FilterParams): # body parameter
...
# With Query() - FastAPI reads from query string
def endpoint(params: FilterParams = Query()): # query parameter
...
Forbidding Extra Parameters
Setting model_config = {"extra": "forbid"} causes FastAPI to return an error if the client sends unknown query parameters:
class FilterParams(BaseModel):
model_config = {"extra": "forbid"}
limit: int = 10
A request to /items/?limit=10&unknown=value would return a 422 Validation Error because unknown is not a recognized parameter. This prevents typos and unexpected input from silently being ignored.
Default Values
Each field in the model can have a default value. When the client omits a parameter, the default is used:
GET /items/ -> limit=10, offset=0, order_by="created_at"
GET /items/?limit=5 -> limit=5, offset=0, order_by="created_at"
GET /items/?limit=5&order_by=name -> limit=5, offset=0, order_by="name"
Reusing Parameter Models
One major benefit is reusability. The same model can be used across multiple endpoints:
@app.get("/items/")
def list_items(filters: FilterParams = Query()):
return {"filters": filters.model_dump()}
@app.get("/users/")
def list_users(filters: FilterParams = Query()):
return {"filters": filters.model_dump()}
Both endpoints now share the same parameter structure, validation, and documentation.
Adding Validation
Since the model is a standard Pydantic model, you can add field-level validation:
from pydantic import BaseModel, Field
class FilterParams(BaseModel):
model_config = {"extra": "forbid"}
limit: int = Field(default=10, ge=1, le=100)
offset: int = Field(default=0, ge=0)
order_by: str = "created_at"
This ensures limit is between 1 and 100, and offset is not negative.
Best Practices
- Use
extra="forbid"to catch typos in query parameter names early - Provide sensible defaults so callers can omit parameters they do not care about
- Reuse models across endpoints that share the same filter logic
- Add Field validation to constrain values at the model level
- Keep models focused -- create separate models for different groups of parameters rather than one large model
What's Next?
You now know how to group query parameters into Pydantic models. This same pattern extends to cookies, headers, and form data, which you will explore in the following lessons.
💡 Hint
Use a Pydantic model with model_config = {'extra': 'forbid'} and annotate it with Query() in your endpoint.
Ready to Practice?
Now that you understand the theory, let's put it into practice with hands-on coding!
Start Interactive Lesson