FastAPI is the fastest-growing Python web framework, designed for building APIs with Python type hints. It offers automatic documentation, data validation, and exceptional performance. This tutorial takes you from basics to a production-ready API.
Why FastAPI?
- Performance: One of the fastest Python frameworks (on par with Node.js and Go)
- Type safety: Automatic validation using Python type hints
- Auto documentation: Swagger UI and ReDoc generated automatically
- Async support: Built on ASGI with native async/await
- Standards-based: OpenAPI and JSON Schema
Getting Started
pip install fastapi uvicorn sqlalchemy pydantic
# main.py
from fastapi import FastAPI
app = FastAPI(title="My API", version="1.0.0")
@app.get("/")
async def root():
return {"message": "Hello, World!"}
@app.get("/items/{item_id}")
async def get_item(item_id: int, q: str = None):
return {"item_id": item_id, "query": q}
# Run: uvicorn main:app --reload
Request Validation with Pydantic
from pydantic import BaseModel, EmailStr, Field
from typing import Optional
class UserCreate(BaseModel):
username: str = Field(..., min_length=3, max_length=50)
email: EmailStr
password: str = Field(..., min_length=8)
full_name: Optional[str] = None
class UserResponse(BaseModel):
id: int
username: str
email: str
full_name: Optional[str]
class Config:
from_attributes = True
@app.post("/users", response_model=UserResponse, status_code=201)
async def create_user(user: UserCreate):
# Pydantic automatically validates the request body
db_user = crud.create_user(db, user)
return db_user
Database Integration with SQLAlchemy
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
DATABASE_URL = "postgresql://user:password@localhost/mydb"
engine = create_engine(DATABASE_URL)
SessionLocal = sessionmaker(bind=engine)
Base = declarative_base()
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True, index=True)
username = Column(String, unique=True, index=True)
email = Column(String, unique=True)
hashed_password = Column(String)
# Dependency
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
@app.get("/users", response_model=list[UserResponse])
async def list_users(skip: int = 0, limit: int = 20, db: Session = Depends(get_db)):
users = db.query(User).offset(skip).limit(limit).all()
return users
Authentication with JWT
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from jose import jwt, JWTError
from datetime import datetime, timedelta
SECRET_KEY = "your-secret-key"
ALGORITHM = "HS256"
security = HTTPBearer()
def create_token(data: dict, expires_delta: timedelta = timedelta(hours=24)):
to_encode = data.copy()
expire = datetime.utcnow() + expires_delta
to_encode.update({"exp": expire})
return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
async def get_current_user(credentials: HTTPAuthorizationCredentials = Depends(security)):
try:
payload = jwt.decode(credentials.credentials, SECRET_KEY, algorithms=[ALGORITHM])
user_id = payload.get("sub")
if user_id is None:
raise HTTPException(status_code=401, detail="Invalid token")
return user_id
except JWTError:
raise HTTPException(status_code=401, detail="Invalid token")
@app.get("/protected")
async def protected_route(user_id: str = Depends(get_current_user)):
return {"message": f"Hello, user {user_id}"}
Error Handling
from fastapi import HTTPException
from fastapi.responses import JSONResponse
@app.exception_handler(ValueError)
async def value_error_handler(request, exc):
return JSONResponse(
status_code=400,
content={"detail": str(exc)}
)
@app.get("/users/{user_id}")
async def get_user(user_id: int, db: Session = Depends(get_db)):
user = db.query(User).filter(User.id == user_id).first()
if not user:
raise HTTPException(status_code=404, detail="User not found")
return user
Testing
from fastapi.testclient import TestClient
client = TestClient(app)
def test_read_root():
response = client.get("/")
assert response.status_code == 200
assert response.json() == {"message": "Hello, World!"}
def test_create_user():
response = client.post("/users", json={
"username": "testuser",
"email": "test@example.com",
"password": "securepassword"
})
assert response.status_code == 201
Production Deployment
# Run with Gunicorn + Uvicorn workers
gunicorn main:app -w 4 -k uvicorn.workers.UvicornWorker --bind 0.0.0.0:8000
FastAPI makes building robust, well-documented APIs a pleasure. Its combination of performance, developer experience, and automatic validation makes it the top choice for new Python API projects in 2026.