Path, Query and Body Parameters
Accept data from the URL and request body with type validation.
What you will learn
- Use path and query parameters
- Model a body with Pydantic
- Return validation errors
Real endpoints take input. FastAPI reads it from three places and validates it using your type hints: the URL path, the query string and the request body.
@app.get("/users/{user_id}")
def get_user(user_id: int):
return {"user_id": user_id}Requesting /users/42 gives you the integer 42. Requesting /users/abc automatically returns an HTTP 422 error explaining that the value is not a valid integer. You wrote no validation code.
Query parameters
Function parameters that are not in the path become query parameters. Give them defaults to make them optional.
from fastapi import Query
@app.get("/search")
def search(q: str, limit: int = 10, page: int = Query(1, ge=1)):
return {"q": q, "limit": limit, "page": page}
# GET /search?q=python&limit=5Query(1, ge=1) adds a rule: the value must be greater than or equal to 1. Similar options: le, min_length, max_length, pattern.
Request body with Pydantic
For JSON bodies, describe the shape with a Pydantic model. FastAPI parses the JSON, validates every field and gives you a typed object.
from pydantic import BaseModel, Field
class Item(BaseModel):
name: str = Field(min_length=1, max_length=50)
price: float = Field(gt=0)
tags: list[str] = []
in_stock: bool = True
@app.post("/items")
def create_item(item: Item):
return {"created": item.name, "total_with_tax": round(item.price * 1.2, 2)}curl -X POST http://127.0.0.1:8000/items \
-H "Content-Type: application/json" \
-d '{"name": "Pen", "price": 1.5}'{"created":"Pen","total_with_tax":1.8}Validation errors
Send {"name": "", "price": -1} and FastAPI replies with status 422 and a list showing exactly which fields failed and why. Clients get clear, consistent errors for free.
@app.put("/items/{item_id}")
def update_item(item_id: int, item: Item, notify: bool = False):
return {"id": item_id, "item": item, "notify": notify}FastAPI infers each source: item_id is in the path, item is a body model, and notify is a query parameter.
Use Optional or str | None = None for values that may be missing, so the docs show them as optional.
Try it yourself
Create POST /users accepting username (3 to 20 characters), email and age (must be at least 13). Return the username in uppercase.
Show solution
from pydantic import BaseModel, Field, EmailStr # pip install email-validator
class User(BaseModel):
username: str = Field(min_length=3, max_length=20)
email: EmailStr
age: int = Field(ge=13)
@app.post("/users")
def create_user(user: User):
return {"username": user.username.upper()}