Skip to main content

Core Decorator and Parameter Reference

Quick-lookup reference for FastAPI route decorators, path/query/body parameters, APIRouter configuration, and response types.

Learning Focus

By the end of this reference you can: quickly recall the syntax and options for every FastAPI decorator, parameter type, and response class.

Route Decorators

@app.get(path, **kwargs)
@app.post(path, **kwargs)
@app.put(path, **kwargs)
@app.patch(path, **kwargs)
@app.delete(path, **kwargs)
@app.options(path, **kwargs)
@app.head(path, **kwargs)
@app.websocket(path)

Decorator Keyword Arguments

status_code=200 HTTP status code for success
response_model=Model Pydantic model for response filtering
tags=["tag"] OpenAPI tag grouping
summary="Short summary" Short description for docs
description="Markdown" Full description for docs
deprecated=False Mark route as deprecated
include_in_schema=True Show/hide in OpenAPI docs
response_description="" Description of the response
operation_id="unique_id" Unique ID for client SDK generation
responses={404: {...}} Additional response codes in schema
dependencies=[...] Route-level dependencies

Path Parameters

# Basic
@app.get("/{item_id}")
async def f(item_id: int): ...

# With constraints
from typing import Annotated
from fastapi import Path

@app.get("/{item_id}")
async def f(item_id: Annotated[int, Path(ge=1, le=1000)]): ...

# Enum
class Color(str, Enum):
red = "red"
blue = "blue"

@app.get("/{color}")
async def f(color: Color): ...

# Path-catching (allows slashes)
@app.get("/{file_path:path}")
async def f(file_path: str): ...

Query Parameters

# Optional with default
async def f(skip: int = 0, limit: int = 10): ...

# Required (no default)
async def f(q: str): ...

# Optional (no default, can be None)
async def f(q: str | None = None): ...

# With constraints
from fastapi import Query

async def f(
q: Annotated[str | None, Query(min_length=2, max_length=50)] = None
): ...

# Multi-value
async def f(tag: Annotated[list[str], Query()] = []): ...

Request Body

# Pydantic model body
async def f(item: ItemCreate): ...

# Multiple bodies
async def f(item: Item, user: User): ...

# Scalar in body
from fastapi import Body
async def f(price: Annotated[float, Body(gt=0, embed=True)]): ...

# Form data
from fastapi import Form
async def f(username: str = Form(...), password: str = Form(...)): ...

# File upload
from fastapi import UploadFile, File
async def f(file: UploadFile = File(...)): ...

Headers and Cookies

from fastapi import Header, Cookie

async def f(
x_token: Annotated[str | None, Header()] = None,
session_id: Annotated[str | None, Cookie()] = None,
): ...

APIRouter

from fastapi import APIRouter

router = APIRouter(
prefix="/items",
tags=["items"],
dependencies=[Depends(auth)],
responses={404: {"description": "Not found"}},
)

app.include_router(
router,
prefix="/api/v1", # Override prefix
tags=["items-v1"], # Override tags
dependencies=[...], # Add extra deps
)

Response Options

from fastapi.responses import (
JSONResponse, # Default JSON
HTMLResponse, # HTML content
PlainTextResponse, # Plain text
FileResponse, # File from disk
StreamingResponse, # Generator/stream
RedirectResponse, # HTTP redirect
Response, # Raw response
)

# Custom headers
@app.get("/")
async def f(response: Response) -> dict:
response.headers["X-Custom"] = "value"
return {}

Common Pitfalls

PitfallCause / SymptomFix
Route not matchedDeclaring /{item_id} after a fixed path like /mePut fixed paths before parameterized paths
422 on query paramUsing int type hint on a string parameter sent by clientUse str for non-numeric identifiers; add Path/Query constraints
Request body not parsedUsing Form(...) where Body(...) is needed (or vice versa)Match the parameter type to the Content-Type header

Hands-On Practice

quick-routing-test.py
from fastapi import FastAPI, APIRouter, Query
from typing import Annotated

app = FastAPI()
router = APIRouter(prefix="/api/v1", tags=["v1"])

@router.get("/items/{item_id}", summary="Get item by ID")
async def get_item(
item_id: int,
q: Annotated[str | None, Query(min_length=2)] = None,
) -> dict:
return {"item_id": item_id, "q": q}

app.include_router(router)

# Run: uvicorn quick-routing-test:app --reload
# Test: curl "http://localhost:8000/api/v1/items/42?q=test"

What's Next