FastAPI Overview
FastAPI is a modern web framework for building REST APIs quickly using Python 3.8+ type hints. Its key strengths are high performance, automatic documentation, and seamless Pydantic integration.
Where FastAPI Fits
Client (Browser / App)
│ HTTP Request
▼
Uvicorn (ASGI Server) ← Converts HTTP to Python events
│
▼
Starlette (ASGI Framework) ← Routing, middleware, WebSocket
│
▼
FastAPI ← Adds type hints + Pydantic + OpenAPI on top of Starlette
# Installation
pip install fastapi uvicorn[standard]
# Optional
pip install python-multipart # File uploads
pip install python-jose[cryptography] # JWT
pip install passlib[bcrypt] # Password hashing
pip install sqlalchemy # ORM
First API
# main.py
from fastapi import FastAPI
app = FastAPI(
title="Learning API",
description="FastAPI learning examples",
version="1.0.0",
)
@app.get("/")
def read_root():
return {"message": "Hello FastAPI"}
@app.get("/items/{item_id}")
def read_item(item_id: int, q: str | None = None):
return {"item_id": item_id, "q": q}
# Run dev server
uvicorn main:app --reload
# Access
# API: http://localhost:8000
# Docs: http://localhost:8000/docs (Swagger UI)
# Docs: http://localhost:8000/redoc (ReDoc)
Path, Query, and Body Parameters
from fastapi import FastAPI
from pydantic import BaseModel
from typing import Annotated
from fastapi import Query, Path, Body
app = FastAPI()
# Path parameter
@app.get("/users/{user_id}")
def get_user(user_id: int):
return {"user_id": user_id}
# Query parameter
@app.get("/search")
def search(
q: str,
skip: int = 0,
limit: Annotated[int, Query(ge=1, le=100)] = 10,
):
return {"q": q, "skip": skip, "limit": limit}
# Request body (Pydantic model)
class Item(BaseModel):
name: str
price: float
is_offer: bool = False
@app.post("/items/")
def create_item(item: Item):
return {"item_name": item.name, "price": item.price}
# Combining path + body
@app.put("/items/{item_id}")
def update_item(item_id: int, item: Item):
return {"item_id": item_id, "item": item}
Response Models and Status Codes
from fastapi import FastAPI, HTTPException, status
from pydantic import BaseModel
from typing import Optional
app = FastAPI()
class UserIn(BaseModel):
name: str
email: str
password: str
class UserOut(BaseModel):
id: int
name: str
email: str
# no password field → automatically excluded from response
fake_db: dict[int, dict] = {}
next_id = 1
@app.post(
"/users/",
response_model=UserOut,
status_code=status.HTTP_201_CREATED,
)
def create_user(user: UserIn):
global next_id
user_data = {"id": next_id, "name": user.name, "email": user.email}
fake_db[next_id] = user_data
next_id += 1
return user_data
@app.get("/users/{user_id}", response_model=UserOut)
def get_user(user_id: int):
if user_id not in fake_db:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"User {user_id} not found",
)
return fake_db[user_id]
Async Endpoints
import asyncio
import httpx
from fastapi import FastAPI
app = FastAPI()
# async def: recommended for async I/O
@app.get("/async-example")
async def async_example():
await asyncio.sleep(0.1) # non-blocking wait
return {"result": "async response"}
# Calling external API (httpx async client)
@app.get("/external")
async def call_external():
async with httpx.AsyncClient() as client:
response = await client.get("https://httpbin.org/uuid")
return response.json()
# def vs async def
# - def: runs in thread pool (blocking OK)
# - async def: runs in event loop (must use await)
@app.get("/sync")
def sync_endpoint():
# CPU-bound or legacy synchronous code
return {"type": "sync"}
@app.get("/async")
async def async_endpoint():
# I/O-bound: DB query, HTTP request, file read
await asyncio.sleep(0)
return {"type": "async"}
App Events and Lifespan
from contextlib import asynccontextmanager
from fastapi import FastAPI
# Python 3.9+: use lifespan for startup/shutdown
@asynccontextmanager
async def lifespan(app: FastAPI):
# Run on startup
print("App start: initialize DB connection pool")
app.state.db_pool = {"connected": True}
yield # app is running
# Run on shutdown
print("App stop: clean up DB connection pool")
app.state.db_pool = None
app = FastAPI(lifespan=lifespan)
@app.get("/health")
def health_check():
return {"status": "ok", "db": app.state.db_pool["connected"]}
Summary
| Concept | Description |
|---|---|
| FastAPI | Starlette + Pydantic + OpenAPI integration |
| Uvicorn | ASGI server (fast async HTTP handling) |
/docs | Auto-generated Swagger UI |
response_model | Specify response schema + auto-filtering |
HTTPException | HTTP error response |
async def | Async endpoint |
lifespan | App startup/shutdown event handling |
FastAPI's core strength is using type hints for documentation, validation, and serialization all at once.