Skip to main content

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 and limit=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

python
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 and limit 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:

json
{
"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.

python
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:

python
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:

python
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 value
  • min_length/max_length: Validates string length
  • regex: Validates against a regular expression
  • title/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:

python
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:

python
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:

json
{
"q": ["foo", "bar"]
}

Practical Examples

Filtering a Product List

Here's a practical example of using query parameters to filter a product list:

python
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:

python
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 and per_page parameters with validation
  • Returns not just the items but also pagination metadata
  • Validates that the requested page exists

Best Practices for Query Parameters

  1. Use descriptive names: Choose clear, understandable names for your parameters.
  2. Provide defaults: Use sensible default values when possible.
  3. Validate inputs: Use type hints and validators to ensure data quality.
  4. Document parameters: Add descriptions for all parameters in your API.
  5. Follow conventions: Use common parameter names like q for search, limit and offset for pagination.
  6. 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

  1. Create an endpoint that accepts search parameters for a book library, including title, author, and publication year.
  2. Implement an API endpoint that supports sorting by multiple fields (e.g., /users/?sort=name:asc,age:desc).
  3. Create a product search API with filtering by multiple categories, price range, and rating.
  4. 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! :)