Path Parameters and Query Parameters — Precision Routing Design
Routing design is like urban road planning—path parameters are like street addresses (precise location), and query parameters are like filter criteria (narrowing down the scope); only when the two work together can you quickly find your destination.
1. What You'll Learn
- Path parameters: automatic type conversion, validation, and
Path()constraints (gt/ge/lt/le) - Query Parameters: Optional/Required, Default Value,
Query()Advanced Validation (alias/description/deprecated) - Rules for the Order of Multi-Parameter Combinations and Common Pitfalls
- String Enumeration Parameter:
Enum—Applications in Paths and Queries - Alice's PriceTracker scenario: Search for prices by product ID; filter by category and price range
2. Alice's True Story
(1) Pain Point: Confusing Product Query API Parameters
Alice's PriceTracker needs to support multiple query methods: exact queries by product ID, filtering by category and price range, and paginated browsing by sort order. Bob passed category=electronics&min_price=10&max_price=999 from the front end, but Alice's Flask code manually parses each parameter. Type conversions are prone to errors, and there are no validations for negative prices or invalid sort fields, leading to frequent production incidents.
(2) Solutions for Parameter Validation in FastAPI
FastAPI uses type hints to automatically parse and validate parameters. Path() and Query() provide declarative constraints, and invalid parameters automatically trigger a 422 error.
from fastapi import FastAPI, Path, Query
app = FastAPI()
@app.get("/products/{product_id}")
async def get_product(
product_id: int = Path(gt=0, description="Product ID must be positive"),
category: str | None = Query(None, max_length=50),
):
return {"product_id": product_id, "category": category}
(3) Revenue
The parameter validation code has been reduced from 30 lines to 3 lines, and 422 error responses now automatically include specific details about the validation failure, allowing Bob to immediately identify which parameter is incorrect. The API documentation also automatically displays all constraints.
3. Detailed Explanation of Path Parameters
(1) Basic Path Parameters
Path parameters are part of the URL path and are defined using the {param} syntax; FastAPI automatically converts them based on type hints.
sequenceDiagram
participant Client
participant Router as FastAPI Router
participant Converter as Type Converter
participant Validator as Path Validator
participant Handler as View Function
Client->>Router: GET /products/42
Router->>Converter: Extract "42" from path
Converter->>Converter: int("42") → 42
Converter->>Validator: product_id=42 (int)
Validator->>Validator: Check gt=0 → 42 > 0 ✓
Validator->>Handler: get_product(product_id=42)
Handler-->>Client: {"product_id": 42}
| Path Parameter Type | URL Example | Python Type | Automatic Conversion |
|---|---|---|---|
| Integer | /products/42 |
int |
"42" → 42 |
| Floating-point numbers | /prices/9.99 |
float |
"9.99" → 9.99 |
| String | /categories/electronics |
str |
As-is |
| Path | /files/src/main.py |
Path |
String containing / |
(1) ▶ Example: Base Path Parameters and Type Conversion
from fastapi import FastAPI
app = FastAPI()
@app.get("/products/{product_id}")
async def get_product(product_id: int):
# FastAPI auto-converts "42" to int(42)
# If user sends /products/abc → 422 error
return {"product_id": product_id, "type": str(type(product_id))}
Output:
INFO: 127.0.0.1:50123 - "GET /api/items HTTP/1.1" 200 OK
Output (
/products/42):
{"product_id": 42, "type": "<class 'int'>"}
(2) Path() Constraint Validation
Path() Add constraints such as numerical ranges and string lengths to path parameters; these are automatically reflected in the OpenAPI documentation.
| Constraint Parameter | Applicable Type | Meaning |
|---|---|---|
gt |
int/float | greater than (>) |
ge |
int/float | greater than or equal to (>=) |
lt |
int/float | less than (<) |
le |
int/float | less than or equal to (<=) |
min_length |
str | Minimum Length |
max_length |
str | Maximum length |
pattern |
str | Regular expression match |
description |
All | OpenAPI Description |
(2) ▶ Example: Path() Numeric Constraints
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/products/{product_id}")
async def get_product(
product_id: int = Path(
gt=0,
le=1000000,
description="Product ID: positive integer, max 1 million",
),
):
return {"product_id": product_id}
Output:
INFO: 127.0.0.1:50123 - "GET /api/items HTTP/1.1" 200 OK
Output (
/products/-1returns 422):
{
"detail": [
{
"loc": ["path", "product_id"],
"msg": "Input should be greater than 0",
"type": "greater_than"
}
]
}
4. Detailed Explanation of Query Parameters
(1) Basic Query Parameters
Query parameters are the key-value pairs that follow ? in the URL. They are declared as function parameters, and parameters with default values are optional.
| Query Parameter Type | Declaration Method | Required |
|---|---|---|
| Required | category: str |
Yes |
| Optional (default) | category: str = "all" |
No |
| Optional (None) | `category: str | None = None` |
(1) ▶ Example: Query Parameter Basics
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/prices")
async def search_prices(
category: str | None = Query(None, max_length=50, description="Product category"),
min_price: float = Query(0.0, ge=0, description="Minimum price in USD"),
max_price: float = Query(999999.0, le=999999, description="Maximum price in USD"),
):
return {
"category": category,
"price_range": f"${min_price} - ${max_price}",
}
Output:
INFO: 127.0.0.1:50123 - "GET /api/items HTTP/1.1" 200 OK
Output (
/prices?category=electronics&min_price=10&max_price=500):
{"category": "electronics", "price_range": "$10.0 - $500.0"}
(2) Query() Advanced Options
| Option | Function | Example |
|---|---|---|
alias |
Parameter aliases (e.g., camel case to snake case) | Query(alias="minPrice") |
deprecated |
Mark as Obsolete | Query(deprecated=True) |
title |
OpenAPI Title | Query(title="Category Filter") |
description |
OpenAPI Description | Query(description="...") |
examples |
Sample Value | Query(examples=["electronics"]) |
(2) ▶ Example: alias and deprecated
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/products")
async def list_products(
sort_by: str = Query(
"name",
alias="sortBy",
description="Sort field: name, price, created_at",
),
old_filter: str | None = Query(
None,
deprecated=True,
description="Use sort_by instead",
),
):
return {"sort_by": sort_by}
Output:
# Function defined successfully
5. Enumeration Parameters
(1) Limiting the Possible Values in a String Enumeration
When a parameter can only take a fixed set of values, use the Enum constraint, and FastAPI will automatically display a drop-down menu in the documentation.
(1) ▶ Example: Enumerating Path Parameters
from enum import Enum
from fastapi import FastAPI
class Category(str, Enum):
electronics = "electronics"
clothing = "clothing"
food = "food"
books = "books"
app = FastAPI()
@app.get("/categories/{category}")
async def get_category(category: Category):
return {
"category": category,
"value": category.value,
"label": category.name,
}
Output:
INFO: 127.0.0.1:50123 - "GET /api/items HTTP/1.1" 200 OK
Output (
/categories/electronics):
{"category": "electronics", "value": "electronics", "label": "electronics"}
(2) ▶ Example: Enumerating Query Parameters and Sorting
from enum import Enum
from fastapi import FastAPI, Query
class SortOrder(str, Enum):
asc = "asc"
desc = "desc"
app = FastAPI()
@app.get("/products")
async def list_products(
sort_order: SortOrder = Query(SortOrder.asc),
limit: int = Query(20, ge=1, le=100),
offset: int = Query(0, ge=0),
):
return {
"sort": sort_order.value,
"limit": limit,
"offset": offset,
}
Output:
# Function defined successfully
6. Combining Multiple Parameters and Pitfalls
(1) Rules for the Order of Parameter Declarations
FastAPI's rules for determining parameter types: Any {param} in the path is a path parameter; otherwise, it is a query parameter (parameters with type annotations are required, and those with default values are optional).
| Order | Parameter Type | Criteria |
|---|---|---|
| 1 | Path Parameter | URL contains {param} |
| 2 | Query parameters (required) | No default value; not included in the path |
| 3 | Query parameters (optional) | Has a default value or None |
(1) ▶ Example: Combining Multiple Parameters—PriceTracker Product Search
from fastapi import FastAPI, Path, Query
from enum import Enum
class Category(str, Enum):
electronics = "electronics"
clothing = "clothing"
food = "food"
app = FastAPI()
@app.get("/products/{product_id}/prices")
async def get_product_prices(
product_id: int = Path(gt=0, description="Product ID"),
category: Category | None = Query(None, description="Filter by category"),
min_price: float = Query(0.0, ge=0, description="Min price in USD"),
max_price: float = Query(99999.0, ge=0, description="Max price in USD"),
sort: str = Query("date", pattern="^(date|price)$"),
limit: int = Query(20, ge=1, le=100),
offset: int = Query(0, ge=0),
):
return {
"product_id": product_id,
"category": category,
"price_range": [min_price, max_price],
"sort": sort,
"pagination": {"limit": limit, "offset": offset},
}
Output:
# Function defined successfully
(2) Common Pitfalls
| Pitfalls | Incorrect Syntax | Correct Syntax |
|---|---|---|
| Path parameter is optional | product_id: int = None |
Path parameter is required |
| Default value conflicts with Query | limit: int = 20, Query(ge=1) |
limit: int = Query(20, ge=1) |
| Optional parameters: None | category: str = None |
`category: str |
Enumerations Do Not Use the str Base Class |
class Cat(Enum): |
class Cat(str, Enum): |
7. Comprehensive Example
Path parameters, query parameters, and enum constraints are the foundation for building flexible APIs. Below, we combine path constraints, query pagination, and enum filtering.
from fastapi import FastAPI, Path, Query
from enum import Enum
app = FastAPI()
class SortOrder(str, Enum):
asc = "asc"
desc = "desc"
PRODUCTS = [{"id": i, "name": f"Product-{i}", "price": i * 10.0} for i in range(1, 101)]
@app.get("/products/{product_id}")
async def get_product(
product_id: int = Path(gt=0, description="Product ID"),
sort: SortOrder = Query(SortOrder.asc),
limit: int = Query(10, ge=1, le=100),
offset: int = Query(0, ge=0),
):
return {
"product_id": product_id,
"sort": sort.value,
"limit": limit,
"offset": offset,
}
Output:
GET /products/5?sort=desc&limit=20&offset=10 → {"product_id":5,"sort":"desc","limit":20,"offset":10}
GET /products/0 → 422 Validation Error (product_id must be > 0)
❓ FAQ
category: str is required, while category: str = "all" is optional. You can also explicitly mark a parameter as required using Query(...).gt=0 means the value must be > 0 (excluding 0), while ge=0 means >= 0 (including 0). ID-type parameters generally use gt=0, while price-type parameters use ge=0.Query(max_length=N) to limit the length of strings, and Query(ge=N, le=M) to limit numerical ranges.📖 Summary
- Path parameters are declared in the URL using
{param}; FastAPI automatically converts and validates them based on type hints. Path()Add numeric range constraints (gt/ge/lt/le) and string constraints (min_length/max_length)- Query parameters are declared as function parameters; those with default values are optional, while those without default values are required.
Query()supports advanced options such asalias/deprecated/description/examples, etc.- Enumeration parameters (
str, Enum) restrict the available values and automatically display a drop-down menu in the document
📝 Exercises
- Basic Problem (Difficulty ⭐): Create a GET endpoint
/items/{item_id}that takesitem_id(a positive integer) as input and returns{"item_id": item_id}. Hint:item_id: int = Path(gt=0) - Advanced Problem (Difficulty ⭐⭐): Create the
/productsquery endpoint for PriceTracker, which supports three query parameters:category(optional string, up to 50 characters),min_price(≥0), andmax_price(≤999999). Hint:Query(None, max_length=50) - Challenge Question (Difficulty: ⭐⭐⭐): Create a
/products/{product_id}/pricesendpoint and, using path parameters (product_id > 0), enumeration query parameters (SortOrder: asc/desc), and pagination parameters (limit 1-100, offset ≥ 0), verify that invalid input returns a 422 error. Hint: DefineSortOrder(str, Enum)and multipleQuery()endpoints.
---|



