Warming up the neural circuits...
By the end of this chapter you will:
Before FastAPI, Python APIs often forced tradeoffs:
FastAPI changed this by turning Python type hints into runtime validation and documentation.
The result is a sharper development loop:
This chapter gives you the minimum practical model to build and reason about real services before we add database and auth complexity.
from fastapi import FastAPI
app = FastAPI(title="Notes API", version="0.1.0")
@app.get("/health")
def health() -> dict[str, str]:
return {"status": "ok"}Run in development:
uvicorn main:app --reloadThe --reload flag watches files and restarts server on change. Use it only in development.
from fastapi import FastAPI, Query
app = FastAPI()
@app.get("/users/{user_id}")
def get_user(user_id: int, include_posts: bool = False, limit: int =
from pydantic import BaseModel, EmailStr
class UserCreate(BaseModel):
name: str
email: EmailStr
age: int | None = None
@app.post("/users")
def create_user(payload
from pydantic import BaseModel
class UserOut(BaseModel):
id: int
name: str
@app.get("/users/{user_id}", response_model=UserOut)
def read_user(user_id: int
By default FastAPI exposes:
/docs for Swagger UI/redoc for ReDoc/openapi.json for machine-readable API schemaThese endpoints are generated from your route declarations and type hints, reducing doc drift.
from fastapi import HTTPException
@app.get("/orders/{order_id}")
def read_order(order_id: int):
if order_id <= 0:
raise HTTPException(status_code=400, detail="order_id must be positive"
Keep docs enabled in development, but review production exposure strategy. Some teams keep /openapi.json internal-only while publishing external docs through a gateway.
| Decision | Good default | Why |
|---|---|---|
| Route naming | Resource-first (/users, /orders/{id}) | Predictable API surface |
| Input validation | Pydantic model per endpoint intent | Strong boundaries and clearer errors |
| Response shape | Explicit response_model | Prevents accidental data leaks |
| Error handling | Raise HTTPException with semantic status | Better client automation |
| Docs usage | Swagger for dev testing, ReDoc for reference | Faster feedback loop |
| Mistake | Why it hurts | Better move |
|---|---|---|
| Returning raw objects directly | Unexpected fields leak to clients | Map to response_model |
Using broad dict for every payload | Weak contracts and unclear errors | Use dedicated Pydantic models |
| Treating 422 as server failure | Misdiagnosed incidents | 422 is client payload/schema mismatch |
Running --reload in production | Unstable process model and overhead | Use production ASGI workers |
| Mixing route and business logic deeply | Hard to test and refactor | Keep route thin; delegate service logic |
FastAPI app skeleton200 JSON with service status/items/{item_id}?limit=...422 for invalid id or out-of-range limitJSON payload with name and emailValid payload accepted; invalid email rejectedInternal object containing password_hashOnly public fields in responseMissing resource, unauthorized call, bad payload404, 401/403, 422 (or 400 for malformed structure)Beginner:
"Why is FastAPI often chosen for Python APIs?"
It combines type-driven validation, support, and automatic OpenAPI docs with low boilerplate.
"What is the difference between path and query parameters?"
Path parameters identify a specific resource, while query parameters usually filter, sort, or paginate.
Senior:
"How do you prevent schema drift between API docs and implementation?"
Keep contracts in typed route and model declarations and treat generated OpenAPI as an artifact checked in CI.
"How would you structure a FastAPI codebase for long-term maintainability?"
Thin routes, service layer boundaries, explicit models, dependency injection for infra concerns, and clear module ownership.
FastAPI app -> typed routes -> automatic validation + OpenAPI docs
Path params identify resources; query params shape retrieval
Use response_model to protect output contracts
Raise HTTPException with intentional status codesWhat does FastAPI use to generate validation rules and OpenAPI docs by default?
If user_id is not an integer or limit is out of bounds, FastAPI returns a 422 with validation details.
The request boundary is strongly validated before your business logic runs.
response_model enforces output shape and strips undeclared fields.
Choose status codes intentionally. Clients depend on these contracts for retries and UX behavior.