Learn / Frameworks / FastAPI / Path, Query and Body Parameters

Beginner 15 min

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=5

Query(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}'
Output
{"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.

Tip

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()}