FastAPI Fundamentals
Path & query params, Pydantic request bodies, dependency injection, and async endpoints
Knowledge Debt detected
You can study this freely — but your score may plateau if these foundations have gaps. The Mastery badge requires them to be solid.
Explanation
FastAPI is the dominant modern Python web framework — built on Starlette + Pydantic, with automatic validation and interactive docs generated from your type hints.
Minimal app:
python from fastapi import FastAPI app = FastAPI() @app.get("/") def read_root(): return {"message": "Hello World"} # Run with: uvicorn main:app --reload
Path and query parameters — type hints drive validation:
python from typing import Optional @app.get("/items/{item_id}") def get_item(item_id: int, q: Optional[str] = None): return {"item_id": item_id, "q": q} - item_id is a **path parameter** — it appears in {} in the route. int means FastAPI validates and converts it, returning a 422 error if the URL segment isn't a valid int. - q is a **query parameter** (?q=...) — any function parameter not in the path or declared as a body model becomes a query parameter. Optional[str] = None` makes it optional.
Request bodies with Pydantic:
python from pydantic import BaseModel class Item(BaseModel): name: str price: float in_stock: bool = True @app.post("/items") def create_item(item: Item): return {"name": item.name, "total": item.price} FastAPI parses the JSON body, validates field types, and gives you a typed Item` object. Invalid bodies (missing fields, wrong types) return 422 automatically — no manual validation code needed.
Dependency Injection with Depends():
python from fastapi import Depends, HTTPException def get_db(): db = SessionLocal() try: yield db finally: db.close() def get_current_user(token: str = Depends(oauth2_scheme)): user = decode_token(token) if not user: raise HTTPException(status_code=401, detail="Invalid token") return user @app.get("/profile") def read_profile(user=Depends(get_current_user), db=Depends(get_db)): return user Depends()` tells FastAPI to call a function (or generator, for setup/teardown) and inject its return value as an argument — used for DB sessions, auth checks, and shared logic across routes.
Async endpoints:
python @app.get("/users/{user_id}") async def get_user(user_id: int): user = await db.fetch_one("SELECT * FROM users WHERE id = :id", {"id": user_id}) return user Use async def when the body awaits I/O (DB, HTTP calls). A plain def` endpoint still works fine — FastAPI runs it in a thread pool.
Route ordering matters:
python @app.get("/users/me") # must come first def read_current_user(): return {"user": "me"} @app.get("/users/{user_id}") # would otherwise match "/users/me" first def read_user(user_id: int): return {"user_id": user_id}
Automatic docs: every FastAPI app gets interactive docs at /docs (Swagger UI) and /redoc, generated entirely from your type hints and Pydantic models.
Examples
CRUD endpoint with path, query params, and a Pydantic body
item_id (path) and include_tax (query) are validated by type hints; the POST body is validated against the Item model
from fastapi import FastAPI
from pydantic import BaseModel
from typing import Optional
app = FastAPI()
class Item(BaseModel):
name: str
price: float
in_stock: bool = True
@app.get("/items/{item_id}")
def get_item(item_id: int, include_tax: Optional[bool] = False):
price = 19.99
if include_tax:
price *= 1.1
return {"item_id": item_id, "price": price}
@app.post("/items", status_code=201)
def create_item(item: Item):
return {"created": item.name, "price": item.price}Dependency injection for DB session and auth
Both dependencies run before the route body; get_db cleans up the session afterward even if the route raises
from fastapi import Depends, HTTPException, FastAPI
app = FastAPI()
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
def get_current_user(token: str = Depends(oauth2_scheme)):
user = decode_token(token)
if user is None:
raise HTTPException(status_code=401, detail="Invalid or missing token")
return user
@app.get("/orders")
def list_orders(user=Depends(get_current_user), db=Depends(get_db)):
return db.query(Order).filter(Order.user_id == user.id).all()How well did you understand this?
Next in FastAPI
FastAPI JWT Auth