codejump

Validate FastAPI requests

Learn how FastAPI separates path, query, and JSON body values, and how Pydantic turns invalid input into useful 422 responses.

1 min readUpdated

3 exercises

Waiting at the end of this page.

Key takeaways

  • Path names come from the route, simple extra parameters come from the query string, and Pydantic models read JSON bodies.
  • Type hints and constraints validate requests before the endpoint runs; invalid data produces a 422 response.
  • Use separate input and output models so a public response exposes only the fields it should.

Where each value comes from

FastAPI uses the route and the parameter type to decide where to read a value. In this endpoint, item_id comes from the path and limit from the query string:

python
from typing import Annotated
from fastapi import FastAPI, Query

app = FastAPI()

@app.get("/items/{item_id}")
def read_item(item_id: int, limit: Annotated[int, Query(ge=1, le=50)] = 10):
    return {"item_id": item_id, "limit": limit}

The request GET /items/7?limit=20 gives the function two integers. GET /items/nope and GET /items/7?limit=0 both fail validation with status 422 before the function runs. The response's detail entries identify the location, such as ["path", "item_id"] or ["query", "limit"].

Describe a JSON body

A Pydantic model parameter reads a request body. Its field constraints are checked before the endpoint runs:

python
from pydantic import BaseModel, Field

class ItemIn(BaseModel):
    name: str = Field(min_length=1)
    price: float = Field(gt=0)

@app.post("/items", status_code=201)
def create_item(item: ItemIn):
    return {"name": item.name, "price": item.price}

A missing name, an empty name, or a nonpositive price gets a 422 response with a body location. The model validates input; it does not store anything by itself. The route must save the item if later requests need to find it.

Keep input and output separate

Use a different output model when the public representation differs from the input. response_model=ItemOut validates and filters the returned value, so internal fields do not leak into JSON. For partial updates, PATCH models usually make fields optional and apply only fields the client actually sent with model_dump(exclude_unset=True); dumping every default can overwrite stored values.

Now practice it

3 exercises

Reading this page is the cheap half. These are the exercises that make you use it.