FastAPI Cheatsheet
Request Body (Pydantic)
Use this FastAPI reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.
Basic Request Body
from fastapi import FastAPI from pydantic import BaseModel app = FastAPI() class Item(BaseModel): name: str price: float is_offer: bool = False # optional with default @app.post("/items") def create_item(item: Item): return item
FastAPI reads the request body as JSON, validates it against Item, and injects the typed object.
Field Types and Defaults
from typing import Optional, List, Dict, Any from pydantic import BaseModel, Field from datetime import datetime from decimal import Decimal from uuid import UUID class Product(BaseModel): id: UUID name: str description: Optional[str] = None # optional, defaults to None price: Decimal tags: List[str] = [] metadata: Dict[str, Any] = {} created_at: datetime
Field() — Validation and Docs Metadata
from pydantic import BaseModel, Field class Item(BaseModel): name: str = Field( ..., # required (Ellipsis) min_length=1, max_length=100, title="Item name", description="Unique name of the item", examples=["Widget"], ) price: float = Field( ..., gt=0, description="Must be positive", ) discount: float = Field(default=0.0, ge=0.0, le=1.0) sku: str = Field(default=None, pattern=r"^[A-Z]{3}-\d{4}$")
Nested Models
class Address(BaseModel): street: str city: str zip_code: str class User(BaseModel): name: str email: str address: Address # nested addresses: List[Address] = [] # list of nested
# JSON sent: # {"name": "Alice", "email": "a@b.com", # "address": {"street": "1 Main St", "city": "NYC", "zip_code": "10001"}}
Multiple Body Parameters
class Item(BaseModel): name: str price: float class User(BaseModel): username: str # FastAPI expects: {"item": {...}, "user": {...}} @app.put("/items/{id}") def update(id: int, item: Item, user: User): return {"item": item, "user": user}
Body() — Singular Extra Body Fields
from fastapi import Body @app.put("/items/{id}") def update( id: int, item: Item, importance: int = Body(..., ge=1, le=5), ): return {"item": item, "importance": importance} # expects: {"item": {...}, "importance": 3}
embed=True — Force Named Key
# Without embed, FastAPI expects: {"name": "foo", "price": 1.0} # With embed=True: {"item": {"name": "foo", "price": 1.0}} @app.post("/items") def create(item: Item = Body(..., embed=True)): return item
model_config and Settings
from pydantic import BaseModel, ConfigDict class Item(BaseModel): model_config = ConfigDict( str_strip_whitespace=True, # strip leading/trailing spaces str_to_upper=False, populate_by_name=True, # allow both alias and field name extra="forbid", # reject unknown fields (default: "ignore") frozen=True, # immutable instances ) name: str price: float
Aliases and Serialization
from pydantic import BaseModel, Field class Item(BaseModel): item_name: str = Field(..., alias="itemName") # JSON key is "itemName" # Parsing: Item.model_validate({"itemName": "Widget"}) # Output: item.model_dump(by_alias=True) → {"itemName": "Widget"}
Schema Examples
class Item(BaseModel): name: str price: float model_config = ConfigDict( json_schema_extra={ "examples": [ {"name": "Widget", "price": 9.99}, ] } )
Custom Validators (Pydantic v2)
from pydantic import BaseModel, field_validator, model_validator class Item(BaseModel): name: str price: float discount: float = 0.0 @field_validator("name") @classmethod def name_must_not_be_empty(cls, v: str) -> str: if not v.strip(): raise ValueError("name cannot be blank") return v.title() @model_validator(mode="after") def discount_lt_price(self) -> "Item": if self.discount >= self.price: raise ValueError("discount must be less than price") return self
Parsing and Serializing Manually
# dict → model item = Item.model_validate({"name": "Widget", "price": 9.99}) # JSON string → model item = Item.model_validate_json('{"name": "Widget", "price": 9.99}') # model → dict d = item.model_dump() d = item.model_dump(exclude_unset=True) # only fields explicitly set d = item.model_dump(exclude_none=True) d = item.model_dump(include={"name"}) d = item.model_dump(exclude={"password"}) # model → JSON string j = item.model_dump_json() # JSON schema schema = Item.model_json_schema()
Form Data (not JSON)
from fastapi import Form # requires: pip install python-multipart @app.post("/login") def login(username: str = Form(...), password: str = Form(...)): return {"username": username} # Content-Type: application/x-www-form-urlencoded
You cannot mix
Formand a Pydantic body model in the same endpoint — they use different content types.
File Uploads
from fastapi import File, UploadFile @app.post("/upload") async def upload(file: UploadFile = File(...)): contents = await file.read() return {"filename": file.filename, "size": len(contents)} # Multiple files: @app.post("/uploads") async def multi_upload(files: List[UploadFile] = File(...)): return [{"filename": f.filename} for f in files]
UploadFile Attributes
| Attribute | Type | Description |
|---|---|---|
filename | str | original filename |
content_type | str | MIME type |
size | int | None | file size in bytes |
headers | Headers | raw headers |
file | SpooledTemporaryFile | file-like object |
UploadFile Methods
| Method | Returns | Notes |
|---|---|---|
await file.read(size) | bytes | read up to size bytes |
await file.write(data) | None | write bytes |
await file.seek(offset) | None | seek to position |
await file.close() | None | close (auto on response) |