FastAPI Query Parameters with Pydantic Models: Pagination, Filtering, and Search
When building REST APIs with Python, handling query parameters is a common requirement. An API might need pagination to limit the number of records returned, filters to narrow down results, and search parameters to find specific items.
FastAPI makes these tasks easier with Pydantic models, Annotated, and Query().
Instead of managing multiple query parameters independently, you can group related parameters into reusable models, validate their values, and keep your API endpoints organized.
In this tutorial, we will build a FastAPI endpoint that supports pagination, tag filtering, and search using Pydantic models.
1. What You Will Learn
By the end of this tutorial, you will understand how to:
Create Pydantic models for query parameters.
Implement pagination using
limitandoffset.Accept multiple filter values in a single request.
Add an optional search parameter.
Validate query parameters with
Field().Test your endpoint using FastAPI's interactive documentation.
2. Install the Required Libraries
Install FastAPI and Uvicorn:
pip install "fastapi>=0.115.0" "uvicorn[standard]"FastAPI 0.115.0 introduced support for extracting query parameters from Pydantic models using Query().
3. Import the Required Modules
Start by importing the necessary classes.
from typing import Annotated
from fastapi import FastAPI, Query
from pydantic import BaseModel, Field
app = FastAPI()Here is what each import does:
FastAPI: Creates the application.Query: Declares and configures query parameters.BaseModel: Defines structured data models.Field: Adds default values and validation constraints.Annotated: Combines a type with additional parameter metadata.
4. Create a Pagination Model
Pagination allows clients to retrieve records in smaller batches rather than requesting an entire dataset.
For example, an API might return 10 records per request by default.
Create a Pydantic model:
class Pagination(BaseModel):
limit: int = Field(default=10, ge=1)
offset: int = Field(default=0, ge=0)Let's understand these fields.
| Parameter | Default | Validation |
|---|---|---|
limit | 10 | Must be at least 1 |
offset | 0 | Must be at least 0 |
The ge argument means "greater than or equal to."
For example, limit=5 and offset=10 requests a batch of up to five records, starting after the first ten records in a typical offset-based pagination implementation.
Important: This model validates pagination values; the actual database query must apply them.
5. Create a Filtering Model
Suppose your API stores articles tagged with topics such as Python, FastAPI, and Data Science.
You can define a model that accepts a list of tags.
class Filters(BaseModel):
tags: list[str] = Field(default_factory=list)Using default_factory=list creates a fresh empty list when no tags are provided.
A request can include multiple values for the same query parameter:
/items/?tags=python&tags=fastapiFastAPI can parse these repeated query parameters into a list:
["python", "fastapi"]This makes it convenient to filter records by multiple tags.
6. Build the FastAPI Endpoint
Now combine the pagination and filtering models with an optional search parameter.
from typing import Annotated
from fastapi import FastAPI, Query
from pydantic import BaseModel, Field
app = FastAPI()
class Pagination(BaseModel):
limit: int = Field(default=10, ge=1)
offset: int = Field(default=0, ge=0)
class Filters(BaseModel):
tags: list[str] = Field(default_factory=list)
@app.get("/items/")
def read_items(
pagination: Annotated[Pagination, Query()],
filters: Annotated[Filters, Query()],
search: str | None = None,
):
return {
"pagination": pagination,
"filters": filters,
"search": search,
}Let's examine the endpoint.
Pagination parameter
pagination: Annotated[Pagination, Query()]FastAPI extracts the model's fields from the query string and validates them against the Pagination model.
Filtering parameter
filters: Annotated[Filters, Query()]The endpoint accepts repeated tags query parameters and groups them into the Filters model.
Search parameter
search: str | None = NoneThe search parameter is optional. If the client does not provide it, its value is None.
This example demonstrates parameter parsing and validation. It does not yet search a database or filter a collection of actual items.
7. Test the API with an Example Request
Start your application by saving the code in main.py and running:
uvicorn main:app --reloadOpen the interactive API documentation:
http://127.0.0.1:8000/docs
You can test the endpoint using this request:
GET /items/?limit=5&offset=0&tags=python&tags=fastapi&search=documentaryThe query string contains:
limit=5: Request up to five records.offset=0: Start from the beginning.tags=python: Include the Python tag.tags=fastapi: Include the FastAPI tag.search=documentary: Provide a search term.
8. Understand the Example Response
Because our endpoint returns the parsed parameters, the response will look like this:
{
"pagination": {
"limit": 5,
"offset": 0
},
"filters": {
"tags": [
"python",
"fastapi"
]
},
"search": "documentary"
}This confirms that FastAPI has extracted and validated the query parameters.
To build a production API, you would use these values to construct a database query or filter an existing dataset.
9. What Happens When Validation Fails?
Pydantic validates the model fields automatically.
For example, this request contains an invalid pagination value:
/items/?limit=0Since limit must be greater than or equal to 1, FastAPI returns a validation error rather than passing the invalid value to your endpoint.
Similarly:
/items/?offset=-5fails because offset cannot be negative.
Automatic validation helps prevent invalid inputs from silently reaching your business logic.
10. Add a Maximum Page Size
For production applications, you may want to prevent clients from requesting excessively large batches.
You can add an upper bound with le, which means "less than or equal to."
class Pagination(BaseModel):
limit: int = Field(default=10, ge=1, le=100)
offset: int = Field(default=0, ge=0)Now the API accepts a limit between 1 and 100.
This is a useful safeguard when the endpoint accesses a database or processes large amounts of data.
11. Benefits of Using Pydantic Models
Why use models instead of writing every query parameter separately?
Cleaner code: Related parameters are grouped into meaningful structures.
Reusable validation: Pagination rules can be reused across endpoints.
Automatic error handling: Invalid values are rejected before your business logic runs.
Improved documentation: FastAPI generates interactive API documentation from your endpoint definitions.
Better maintainability: As your API grows, structured parameters are easier to understand and manage.
12. Important Considerations
Before using this pattern in a production application, remember:
Use a FastAPI version that supports query parameter models.
Query parameters are public inputs and should be validated.
Pagination models do not automatically execute database pagination.
Filter models do not automatically filter database records.
Search parameters need actual search logic.
Repeated query parameters, such as
tags=python&tags=fastapi, are a convenient way to pass lists.For very large datasets, cursor-based pagination may be more efficient than offset-based pagination.
Also, Annotated is a standard Python typing feature. It is not specific to FastAPI, but FastAPI uses it to associate parameter metadata with type declarations.
Conclusion
FastAPI and Pydantic provide a clean way to organize and validate query parameters in modern Python APIs.
By combining Annotated, Query(), BaseModel, and Field(), you can create structured endpoints that support pagination, filtering, and search with relatively little code.
The example in this tutorial demonstrates how to accept multiple tags, validate pagination values, and parse an optional search term.
Key takeaway: Use Pydantic models to structure your API inputs, validate them early, and keep your endpoint logic easy to maintain.
Continue exploring Python, FastAPI, backend development, and practical programming tutorials at CLCODING.
Website: https://whatsapp.com/channel/0029Va5BbiT9xVJXygonSX0G
Frequently Asked Questions
Can FastAPI use Pydantic models for query parameters?
Yes. With FastAPI 0.115.0 or later, you can use a Pydantic model with Annotated[Model, Query()] to extract and validate query parameters.
How do I pass multiple tags to FastAPI?
Repeat the query parameter, such as ?tags=python&tags=fastapi. FastAPI can parse the values into a list of strings.
Does pagination automatically limit database results?
No. The model validates limit and offset. Your database query must apply those values to retrieve the requested records.
What is the purpose of Field()?
Field() lets you specify defaults, validation constraints, and other field metadata in a Pydantic model.
#FastAPI #Python #Pydantic #RESTAPI #BackendDevelopment #PythonTutorial #CLCODING
%60,%20you%20can%20build%20cleaner,%20more%20m.png)
