What is FastAPI
FastAPI is a modern Python web framework for building APIs that combines speed, automatic documentation, and strong type safety into a single ergonomic package. Released in 2018 by Sebastián Ramírez, it has become one of the most starred Python projects on GitHub.
By the end of this lesson you can: describe FastAPI's architecture, explain why it generates OpenAPI docs automatically, and confidently choose it over Flask or Django for API-first projects.
The Problem FastAPI Solves
Building APIs in Flask or Django requires significant boilerplate: manual validation, hand-written serializers, separately maintained API documentation, and no enforcement that your docs match your actual code. As the codebase grows, these gaps cause bugs and maintenance debt.
FastAPI's core insight: your Python type hints are your contract. Write them once, and FastAPI generates validators, serializers, and OpenAPI documentation automatically.
How FastAPI Works
FastAPI is built on two libraries:
- Starlette — the ASGI web framework that handles routing, middleware, WebSockets, and HTTP primitives
- Pydantic — the data validation library that reads your type hints and enforces them at runtime
When you annotate a route function parameter with a Pydantic model, FastAPI automatically:
- Parses the incoming request JSON
- Validates each field against the model schema
- Returns a
422 Unprocessable Entitywith detailed errors if validation fails - Passes a fully typed Python object to your handler
FastAPI vs Flask vs Django
| Feature | FastAPI | Flask | Django / DRF |
|---|---|---|---|
| Async native | ✅ Built-in | ⚠️ Gevent/Quart only | ⚠️ Channels addon |
| Request validation | ✅ Pydantic automatic | ❌ Manual | ✅ Serializers (DRF) |
| OpenAPI generation | ✅ Automatic | Plugin needed | drf-spectacular |
| Response serialization | ✅ Automatic | ❌ Manual | ✅ DRF Serializers |
| Type safety | ✅ End-to-end | ❌ | Partial |
| ORM bundled | ❌ Choose your own | ❌ | ✅ Django ORM |
| Admin panel | ❌ | ❌ | ✅ |
| Performance | ⚡ Very fast | Moderate | Moderate |
| Learning curve | Low-Medium | Low | Medium-High |
FastAPI does not ship with an ORM or admin panel by design. Use it with SQLAlchemy, Tortoise ORM, or any other library you prefer.
What "Automatic Documentation" Means
Add one decorator. Open /docs. Your API is fully documented with request/response schemas, example payloads, and a live "Try it out" button — with zero additional code.
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI(title="Demo API", version="1.0.0")
class Item(BaseModel):
name: str
price: float
@app.post("/items/", summary="Create an item")
async def create_item(item: Item) -> Item:
return item
Visiting http://localhost:8000/docs shows:
- POST
/items/with a JSON body schema derived fromItem - Response schema (also
Item) - Example payloads generated from field types
The ASGI Foundation
FastAPI uses ASGI (Asynchronous Server Gateway Interface), not the older WSGI. This distinction matters:
| WSGI | ASGI | |
|---|---|---|
| Async support | ❌ Blocking | ✅ Non-blocking |
| WebSockets | ❌ | ✅ |
| Server-Sent Events | ❌ | ✅ |
| Typical servers | Gunicorn + sync | Uvicorn / Hypercorn |
If you are coming from Flask or Django, never call blocking I/O (database queries, file reads, HTTP requests) without await in an async route. This stalls the entire event loop. Module 1.4 covers this in detail.
Common Pitfalls
| Pitfall | Cause / Symptom | Fix |
|---|---|---|
| "I can't find my route" | Route defined after app.include_router or incorrect prefix | Check router prefix and include_router call order |
422 Unprocessable Entity on every request | Request body doesn't match the Pydantic model | Read the detail field in the response — it lists every failing field |
| Sync DB calls blocking the event loop | Using SQLAlchemy sync engine inside async def | Use async engine (asyncpg) or run sync calls in threadpool |
| Docs not reflecting latest changes | Cached browser or stale Uvicorn process | Hard-refresh browser, restart Uvicorn with --reload |
| Pydantic v1 patterns failing | Migrated to FastAPI 0.100+ which uses Pydantic v2 | Replace class Config with model_config = ConfigDict(...) |
Hands-On Practice
# 1) Install
pip install "fastapi[standard]>=0.111"
# 2) Create a minimal app
cat > explore.py << 'EOF'
from fastapi import FastAPI
from pydantic import BaseModel
from typing import Annotated
app = FastAPI(title="Explore FastAPI")
class Greeting(BaseModel):
message: str
language: str = "en"
@app.get("/")
async def root() -> dict:
return {"hello": "world"}
@app.post("/greet")
async def greet(body: Greeting) -> Greeting:
return body
EOF
# 3) Run
uvicorn explore:app --reload
# 4) Test in another terminal
curl http://localhost:8000/
curl -X POST http://localhost:8000/greet \
-H "Content-Type: application/json" \
-d '{"message": "Bonjour", "language": "fr"}'
# 5) View the auto-generated docs
# Open: http://localhost:8000/docs
Expected output from curl root:
{"hello": "world"}
Expected output from curl greet:
{"message": "Bonjour", "language": "fr"}