Path Operations & Pydantic
Path Operations & Pydantic App Setup & Routing from fastapi import FastAPI, HTTPException, status from fastapi.middleware.cors import CORSMiddleware app = FastA…
Path Operations & Pydantic
App Setup & Routing
from fastapi import FastAPI, HTTPException, status
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI(
title="My API",
description="FastAPI example",
version="1.0.0",
docs_url="/docs", # Swagger UI
redoc_url="/redoc", # ReDoc
)
app.add_middleware(
CORSMiddleware,
allow_origins=["https://myapp.com"],
allow_methods=["*"],
allow_headers=["*"],
allow_credentials=True,
)
# Path operations
@app.get("/")
def root():
return {"message": "Hello World"}
@app.get("/items/{item_id}")
def get_item(item_id: int): # auto-validates int
return {"id": item_id}
# Query parameters
@app.get("/users")
def list_users(
page: int = 1,
limit: int = 10,
search: str | None = None, # optional
active: bool = True,
):
return {"page": page, "limit": limit, "search": search}
# Multiple path params
@app.get("/users/{user_id}/posts/{post_id}")
def get_user_post(user_id: int, post_id: int):
return {"user_id": user_id, "post_id": post_id}
# Response status codes
@app.post("/users", status_code=status.HTTP_201_CREATED)
def create_user(user: UserCreate):
return {"id": 1, **user.model_dump()}
@app.delete("/users/{user_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_user(user_id: int):
pass
# HTTP errors
def get_or_404(item_id: int):
item = db.get(item_id)
if not item:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"Item {item_id} not found",
)
return itemPydantic Models
from pydantic import BaseModel, Field, EmailStr, field_validator, model_validator
from typing import Optional
from datetime import datetime
from enum import Enum
class UserRole(str, Enum):
admin = "admin"
user = "user"
class UserBase(BaseModel):
email: EmailStr
name: str = Field(..., min_length=2, max_length=100)
role: UserRole = UserRole.user
class UserCreate(UserBase):
password: str = Field(..., min_length=8)
@field_validator("password")
@classmethod
def password_must_have_uppercase(cls, v: str) -> str:
if not any(c.isupper() for c in v):
raise ValueError("Password must contain uppercase letter")
return v
class UserResponse(UserBase):
id: int
created_at: datetime
model_config = {"from_attributes": True} # enables ORM mode
class UserUpdate(BaseModel):
name: Optional[str] = Field(None, min_length=2)
bio: Optional[str] = None
# Nested models
class Address(BaseModel):
street: str
city: str
country: str = "US"
class UserWithAddress(UserBase):
address: Optional[Address] = None
tags: list[str] = []
metadata: dict[str, str] = {}
# Usage
user = UserCreate(email="user@example.com", name="Alice", password="Password1")
print(user.model_dump())
print(user.model_dump_json())
user_dict = {"email": "a@b.com", "name": "Bob", "password": "StrongPass1"}
user = UserCreate.model_validate(user_dict)Request Body & Response Models
from fastapi import FastAPI, Body
from fastapi.responses import JSONResponse, StreamingResponse
# Request body
@app.post("/users", response_model=UserResponse, status_code=201)
def create_user(user: UserCreate) -> UserResponse:
# response_model filters output — only UserResponse fields returned
db_user = create_in_db(user)
return db_user
# Multiple body params
@app.put("/users/{user_id}")
def update_user(
user_id: int,
user: UserUpdate,
reason: str = Body(..., embed=True), # extra body field
):
return {"id": user_id, "reason": reason, **user.model_dump(exclude_none=True)}
# response_model_exclude / include
@app.get("/users/me", response_model=UserResponse, response_model_exclude={"password"})
def get_me():
...
# List response
@app.get("/users", response_model=list[UserResponse])
def list_users():
return db.get_all_users()
# Custom response
@app.get("/export")
def export():
def generate():
yield "col1,col2
"
yield "a,b
"
return StreamingResponse(generate(), media_type="text/csv",
headers={"Content-Disposition": "attachment; filename=data.csv"})Routers (APIRouter)
# routers/users.py
from fastapi import APIRouter
router = APIRouter(prefix="/users", tags=["users"])
@router.get("/")
def list_users():
return []
@router.get("/{user_id}")
def get_user(user_id: int):
return {"id": user_id}
# main.py
from routers import users, posts, auth
app.include_router(auth.router, prefix="/auth", tags=["auth"])
app.include_router(users.router)
app.include_router(posts.router, prefix="/api/v1")