FastAPI Query Parameters
In this tutorial, you'll learn how to work with query parameters in FastAPI. Query parameters are a crucial part of API development, allowing clients to filter, sort, and paginate data without changing the endpoint URL structure.
What Are Query Parameters?
Query parameters are key-value pairs that appear after a question mark (?
) in a URL. They're used to send additional information to the server when making a request. For example:
https://api.example.com/items?skip=0&limit=10
In this URL:
skip=0
andlimit=10
are query parameters- They're separated from the base URL by a question mark (
?
) - Multiple parameters are separated by an ampersand (
&
)
Basic Query Parameters in FastAPI
FastAPI makes it incredibly easy to work with query parameters. By default, any function parameter in your path operation function that isn't part of the path parameters is interpreted as a query parameter.
Example: Simple Query Parameters
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/")
async def read_items(skip: int = 0, limit: int = 10):
return {"skip": skip, "limit": limit}
In this example:
skip
andlimit
are automatically interpreted as query parameters- They have default values (0 and 10 respectively)
- They're defined with type annotations (
int
), which FastAPI uses for validation
When you access the URL /items/?skip=20&limit=30
, you'll receive:
{
"skip": 20,
"limit": 30
}
Optional Query Parameters
If you set a default value for a parameter, it becomes optional. If you don't provide a default value, the parameter is required.
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/")
async def read_items(skip: int = 0, limit: int = 10, q: str = None):
response = {"skip": skip, "limit": limit}
if q:
response.update({"q": q})
return response
In this example, q
is an optional string parameter. If you don't provide it in the URL, it will be None
.
Type Conversion and Validation
FastAPI automatically converts and validates query parameters based on the type annotations:
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/")
async def read_items(id: int, price: float, is_available: bool, name: str = None):
return {
"id": id,
"price": price,
"is_available": is_available,
"name": name
}
When you access /items/?id=123&price=19.99&is_available=true
, FastAPI will:
- Convert
id
to an integer (123) - Convert
price
to a float (19.99) - Convert
is_available
to a boolean (True)
If any conversion fails, FastAPI will return an appropriate error response.
Using the Query Class
For more advanced control over query parameters, FastAPI provides the Query
class:
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(
q: str = Query(
default=None,
min_length=3,
max_length=50,
title="Query string",
description="Query string for the items to search"
)
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results.update({"q": q})
return results
The Query
class provides many parameters for validation and documentation:
default
: Sets the default valuemin_length
/max_length
: Validates string lengthregex
: Validates against a regular expressiontitle
/description
: Adds metadata for the API documentation
Required Query Parameters
To make a query parameter required, you can use Query
without a default value or with ...
as the default:
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items/")
async def read_items(q: str = Query(default=..., min_length=3)):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
results.update({"q": q})
return results
In this example, q
is a required parameter with a minimum length of 3 characters.
List/Array Query Parameters
You can receive multiple values for the same query parameter by declaring it as a list:
from fastapi import FastAPI, Query
from typing import List
app = FastAPI()
@app.get("/items/")
async def read_items(q: List[str] = Query(default=None)):
query_items = {"q": q}
return query_items
This allows you to use URLs like /items/?q=foo&q=bar
which would result in:
{
"q": ["foo", "bar"]
}
Practical Examples
Filtering a Product List
Here's a practical example of using query parameters to filter a product list:
from fastapi import FastAPI, Query
from typing import List, Optional
from pydantic import BaseModel
app = FastAPI()
class Product(BaseModel):
id: int
name: str
category: str
price: float
# Sample database
products = [
Product(id=1, name="Laptop", category="Electronics", price=999.99),
Product(id=2, name="Smartphone", category="Electronics", price=699.99),
Product(id=3, name="T-shirt", category="Clothing", price=19.99),
Product(id=4, name="Jeans", category="Clothing", price=49.99),
]
@app.get("/products/", response_model=List[Product])
async def get_products(
category: Optional[str] = None,
min_price: Optional[float] = None,
max_price: Optional[float] = None
):
results = products
if category:
results = [p for p in results if p.category == category]
if min_price is not None:
results = [p for p in results if p.price >= min_price]
if max_price is not None:
results = [p for p in results if p.price <= max_price]
return results
This endpoint allows filtering products by:
- Category (
/products/?category=Electronics
) - Minimum price (
/products/?min_price=50
) - Maximum price (
/products/?max_price=500
) - Any combination (
/products/?category=Electronics&min_price=500&max_price=1000
)
Pagination Example
Here's how to implement pagination using query parameters:
from fastapi import FastAPI, Query, HTTPException
from typing import List, Dict, Any
from math import ceil
app = FastAPI()
# Sample database
items = [{"id": i, "name": f"Item {i}"} for i in range(1, 101)]
@app.get("/items/")
async def get_items(
page: int = Query(1, ge=1, description="Page number"),
per_page: int = Query(10, ge=1, le=100, description="Items per page")
):
start_idx = (page - 1) * per_page
end_idx = start_idx + per_page
# Calculate total pages
total_items = len(items)
total_pages = ceil(total_items / per_page)
# Check if page exists
if page > total_pages and total_items > 0:
raise HTTPException(status_code=404, detail="Page not found")
# Get items for the requested page
paginated_items = items[start_idx:end_idx]
return {
"items": paginated_items,
"pagination": {
"total_items": total_items,
"total_pages": total_pages,
"current_page": page,
"per_page": per_page,
"has_next": page < total_pages,
"has_prev": page > 1
}
}
This example:
- Uses
page
andper_page
parameters with validation - Returns not just the items but also pagination metadata
- Validates that the requested page exists
Best Practices for Query Parameters
- Use descriptive names: Choose clear, understandable names for your parameters.
- Provide defaults: Use sensible default values when possible.
- Validate inputs: Use type hints and validators to ensure data quality.
- Document parameters: Add descriptions for all parameters in your API.
- Follow conventions: Use common parameter names like
q
for search,limit
andoffset
for pagination. - Be consistent: Use the same parameter names and formats across your API.
Summary
FastAPI makes working with query parameters simple and powerful:
- Query parameters are automatically detected and parsed
- Type validation and conversion is handled automatically
- The
Query
class provides advanced validation and documentation options - You can create complex filtering, searching, and pagination systems
Query parameters are essential for creating flexible APIs that allow clients to request exactly the data they need, in the format and quantity they require.
Practice Exercises
- Create an endpoint that accepts search parameters for a book library, including title, author, and publication year.
- Implement an API endpoint that supports sorting by multiple fields (e.g.,
/users/?sort=name:asc,age:desc
). - Create a product search API with filtering by multiple categories, price range, and rating.
- Implement a paginated endpoint that returns a list of users with configurable page size and number.
Additional Resources
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)