Routing and Endpoints
Learn how to create and manage routes and endpoints effectively in FastAPI applications.
Content
Query Parameters
Versions:
Watch & Learn
AI-discovered learning video
Sign in to watch the learning video for this topic.
Query Parameters — The Chill Siblings of Path Parameters (But Just As Powerful)
"Path params are the passport, query params are the search filters. Both get you in — but one asks politely for extra details."
You already know how to carve routes and grab path parameters from the URL (remember: /items/{item_id} was our jam). Now meet their more flexible cousins: query parameters. They’re the tiny question marks at the end of URLs that let users filter, paginate, and basically make your endpoints behave like a decent search engine instead of a brick of JSON.
What are Query Parameters? (Short answer)
- They appear after the
?in a URL:/items/?q=phone&page=2. - They are typically optional (unless you explicitly make them required).
- Use them for filters, sorts, pagination, and toggles — data that modifies the response but isn't part of the resource identity.
Think: path params = who/which resource; query params = how you want it returned.
How FastAPI reads query params (and how you tell it what you want)
FastAPI uses Python type hints and function parameters. If a function parameter is not a path parameter, it becomes a query param (or body param in complex cases). That means:
- If your route contains
{name}, a parameternameis a path param. - Otherwise, a parameter is treated as a query parameter (or as a body param if it's a Pydantic model).
Pro tip: For readability, put path parameters first in your function signature and query parameters after.
Basic example
from fastapi import FastAPI
from typing import Optional
app = FastAPI()
@app.get('/items/')
def read_items(q: Optional[str] = None):
return {'q': q}
Calling /items/?q=hammer returns { "q": "hammer" }.
Making query params required or validated: Query()
Use fastapi.Query to add metadata, defaults, and validation rules.
from fastapi import Query
from typing import Optional
@app.get('/search/')
def search(
q: Optional[str] = Query(
None,
min_length=3,
max_length=50,
title='Search string',
description='Term to search for in the items'
)
):
return {'q': q}
- Make a param required:
q: str = Query(...)(Ellipsis means "no default — required"). - Add validation:
min_length,max_length,gt,ge,lt,lefor numeric checks. - Add doc metadata:
title,description,deprecated=True,example=....
Try it:
/docsor/redocwill display your descriptions and show example values automatically.
Common practical patterns
Pagination (classic)
@app.get('/items/')
def list_items(page: int = Query(1, ge=1), size: int = Query(10, ge=1, le=100)):
offset = (page - 1) * size
return {'offset': offset, 'limit': size}
Usage: /items/?page=2&size=25
Filtering & search
from typing import List
@app.get('/products/')
def products(q: Optional[str] = Query(None), tags: List[str] = Query([])):
# tags passed like: ?tags=fastapi&tags=python
return {'q': q, 'tags': tags}
- Lists are typically passed by repeating the key:
?tags=python&tags=fastapi. - Avoid using mutable defaults in general code patterns — FastAPI's Query([]) is idiomatic for query list defaults.
Booleans and flags
Booleans are parsed from true/false values: /items/?hidden=true. Be explicit with types so FastAPI parses them correctly.
Advanced features and ergonomics
- Aliases: expose a different name in the URL than the Python arg
q: Optional[str] = Query(None, alias='search-term')
# -> /items/?search-term=foo
- Deprecation flag:
Query(None, deprecated=True)— signals client libs and docs that this param is dying. - Examples in docs:
Query(None, examples={'a': {'value': 'x', 'description': 'An example'}})
Contrasting with Path Params and Request Bodies
- Path params are part of the path (identity), required by definition, and typed.
- Query params are modifiers: optional, great for filtering/pagination/sorting.
- Request bodies (JSON) are for large structured data (create/update operations).
Quote-worthy rule:
If it identifies the resource: path param. If it modifies the response: query param. If it carries a complex object: request body.
Common pitfalls & gotchas
- Naming collisions: If a function param name matches a path param, FastAPI will treat it as path param. Avoid ambiguous names.
- Required vs optional confusion:
q: str = Noneis optional;q: str = Query(...)is required. - List inputs: prefer repeating keys (
?tag=a&tag=b) rather than trying fancy comma parsing — it's clear and standard. - Validation errors produce a 422 response with a helpful JSON body — handy in development, annoying in prod if unhandled.
Quick cheat-sheet table
| Use case | Declaration | URL example |
|---|---|---|
| Optional string | q: Optional[str] = None |
/items/?q=blue |
| Required string | q: str = Query(...) |
/items/?q=must |
| Int with bounds | page: int = Query(1, ge=1) |
/items/?page=2 |
| List of strings | tags: List[str] = Query([]) |
/items/?tags=py&tags=fastapi |
| Alias | q: str = Query(None, alias='search-term') |
/items/?search-term=xyz |
Tiny real-world example — search endpoint
from fastapi import FastAPI, Query
from typing import List, Optional
app = FastAPI()
@app.get('/search/')
def search(
q: Optional[str] = Query(None, min_length=3, description='Search term'),
page: int = Query(1, ge=1),
per_page: int = Query(10, ge=1, le=100),
tags: List[str] = Query([])
):
# pretend we query a DB here
return {
'query': q,
'page': page,
'per_page': per_page,
'tags': tags,
}
Useful: /search/?q=fastapi&page=1&per_page=20&tags=python&tags=web
Wrap-up & Key Takeaways
- Query parameters = flexible modifiers. Use them for filters, sorts, pagination, and flags.
- Control their behavior with type hints and
fastapi.Query()for defaults, requirements, and validation. - Lists come in handy for multi-value filters; repeat the key in the URL.
- Use aliases, descriptions, and examples to make your auto-generated docs actually useful.
Final thought: treat query params like the polite, overachieving assistant in your API kitchen — they don’t define the dish (the resource), but they sure make it taste exactly the way your user wants.
Comments (0)
Please sign in to leave a comment.
No comments yet. Be the first to comment!