Difficulty: Beginner
Query parameters are key-value pairs that appear after the question mark in a URL, like /items?skip=0&limit=10. In FastAPI, any function parameter that is not a path parameter is automatically treated as a query parameter. This makes it intuitive to add filtering, pagination, and other optional parameters to your endpoints.
When you define a function parameter with a default value, FastAPI treats it as an optional query parameter. For example, def list_items(skip: int = 0, limit: int = 10) creates two optional query parameters with defaults. Clients can call /items (uses defaults), /items?skip=20 (overrides skip only), or /items?skip=20&limit=5 (overrides both).
A parameter without a default value is required. If you write def search(q: str), the client must provide the q query parameter. A request to /search without ?q=something will result in a 422 validation error. This is a clean way to enforce that certain parameters are always provided.
FastAPI automatically converts query parameter values from strings to the annotated type. The URL always transmits values as strings, but FastAPI handles the conversion. If you declare limit: int, FastAPI converts '10' to 10. If conversion fails (like passing 'abc' for an int), FastAPI returns a 422 error with a clear message.
Boolean query parameters have special handling. FastAPI accepts various truthy and falsy values: true/false, yes/no, 1/0, on/off (case-insensitive). So /items?active=true, /items?active=yes, /items?active=1 all set active to True.
You can also receive multiple values for the same query parameter using List types. For example, def filter_items(tag: list[str] = Query(default=[])) accepts /items?tag=python&tag=fastapi and provides tag as ['python', 'fastapi']. This is useful for multi-select filters.
Query parameters are ideal for optional filters, pagination, sorting, and search functionality. They keep the URL clean by separating the resource identifier (path) from the modifiers (query). A well-designed API uses path parameters for resource identification and query parameters for everything else.
from fastapi import FastAPI
app = FastAPI()
@app.get("/items")
def list_items(skip: int = 0, limit: int = 10):
"""Both parameters are optional with defaults"""
return {"skip": skip, "limit": limit}
# GET /items -> {"skip": 0, "limit": 10}
# GET /items?skip=20 -> {"skip": 20, "limit": 10}
# GET /items?limit=5 -> {"skip": 0, "limit": 5}
# GET /items?skip=20&limit=5 -> {"skip": 20, "limit": 5}
@app.get("/search")
def search(q: str):
"""q is required (no default value)"""
return {"query": q}
# GET /search?q=fastapi -> {"query": "fastapi"}
# GET /search -> 422 Error: q is required
Parameters with default values are optional. Parameters without defaults are required. FastAPI distinguishes path parameters (in the URL path) from query parameters (everything else) automatically.
from fastapi import FastAPI
app = FastAPI()
@app.get("/items")
def list_items(
skip: int = 0,
limit: int = 10,
active: bool = True,
):
return {"skip": skip, "limit": limit, "active": active}
# Boolean values accepted:
# GET /items?active=true -> active = True
# GET /items?active=false -> active = False
# GET /items?active=yes -> active = True
# GET /items?active=no -> active = False
# GET /items?active=1 -> active = True
# GET /items?active=0 -> active = False
# GET /items?active=on -> active = True
@app.get("/convert")
def conversion_demo(price: float, count: int, name: str):
return {"price": price, "count": count, "name": name}
# GET /convert?price=9.99&count=5&name=Widget
# price is float, count is int, name is str
FastAPI converts query strings to the annotated type. Boolean parameters accept multiple truthy/falsy string representations. Type conversion errors automatically return 422 validation errors.
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/items")
def filter_items(
tag: list[str] = Query(default=[]),
category: list[str] = Query(default=[]),
):
return {"tags": tag, "categories": category}
# GET /items?tag=python&tag=fastapi&category=web
# -> {"tags": ["python", "fastapi"], "categories": ["web"]}
# GET /items
# -> {"tags": [], "categories": []}
@app.get("/filter")
def filter_with_ids(
ids: list[int] = Query(default=[]),
):
return {"ids": ids}
# GET /filter?ids=1&ids=2&ids=3
# -> {"ids": [1, 2, 3]}
Use list[str] or list[int] with Query() to accept multiple values for the same parameter. The client repeats the parameter name for each value. This is common for filters like tags or categories.
Query Parameters, Default Values, Required Params, Type Conversion, Multiple Values