Python
FastAPI Complete Guide
Master FastAPI development from setup to production including async programming, REST APIs, authentication, database integration, testing, performance optimisation, and enterprise deployment strategies.
What you'll learn
- Build high-performance async REST APIs with FastAPI
- Validate request/response with Pydantic v2 models
- Implement OAuth2 + JWT authentication
- Integrate SQLAlchemy 2.0 async ORM with PostgreSQL
- Write tests with pytest-asyncio and httpx
- Add background tasks and WebSocket support
- Deploy with Docker and uvicorn workers
Setup & First API
Python
1pip install fastapi uvicorn[standard] pydantic-settings
2
3# main.py
4from fastapi import FastAPI
5from contextlib import asynccontextmanager
6
7@asynccontextmanager
8async def lifespan(app: FastAPI):
9 # startup
10 yield
11 # shutdown
12
13app = FastAPI(title="My API", version="1.0.0", lifespan=lifespan)
14
15@app.get("/health")
16async def health() -> dict[str, str]:
17 return {"status": "ok"}
18
19# Run
20uvicorn main:app --reload --port 8000Pydantic Models
Python
1from pydantic import BaseModel, EmailStr, field_validator
2from datetime import datetime
3
4class UserCreate(BaseModel):
5 name: str
6 email: EmailStr
7 password: str
8
9 @field_validator('password')
10 @classmethod
11 def password_strength(cls, v: str) -> str:
12 if len(v) < 8:
13 raise ValueError('Password must be at least 8 characters')
14 return v
15
16class UserResponse(BaseModel):
17 id: int
18 name: str
19 email: EmailStr
20 created_at: datetime
21
22 model_config = {"from_attributes": True}
23
24@app.post("/users", response_model=UserResponse, status_code=201)
25async def create_user(data: UserCreate) -> UserResponse:
26 ...Dependency Injection
Python
1from fastapi import Depends
2from sqlalchemy.ext.asyncio import AsyncSession
3from .database import async_session_maker
4
5async def get_db() -> AsyncSession:
6 async with async_session_maker() as session:
7 yield session
8
9# Inject into any route
10@app.get("/courses")
11async def list_courses(db: AsyncSession = Depends(get_db)):
12 result = await db.execute(select(Course).where(Course.is_published == True))
13 return result.scalars().all()JWT Authentication
Python
1pip install python-jose[cryptography] passlib[bcrypt]
2
3from jose import JWTError, jwt
4from passlib.context import CryptContext
5from fastapi.security import OAuth2PasswordBearer
6
7pwd_context = CryptContext(schemes=["bcrypt"])
8oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/auth/token")
9SECRET_KEY = os.environ["JWT_SECRET"]
10ALGORITHM = "HS256"
11
12def create_access_token(sub: str) -> str:
13 expire = datetime.utcnow() + timedelta(minutes=15)
14 return jwt.encode({"sub": sub, "exp": expire}, SECRET_KEY, algorithm=ALGORITHM)
15
16async def get_current_user(token: str = Depends(oauth2_scheme), db=Depends(get_db)):
17 try:
18 payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
19 user_id = payload.get("sub")
20 except JWTError:
21 raise HTTPException(status_code=401, detail="Invalid token")
22 user = await db.get(User, user_id)
23 if not user:
24 raise HTTPException(status_code=401)
25 return userAsync Database
Python
1pip install sqlalchemy asyncpg alembic
2
3# database.py
4from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker
5from sqlalchemy.orm import DeclarativeBase
6
7DATABASE_URL = os.environ["DATABASE_URL"].replace("postgresql://", "postgresql+asyncpg://")
8engine = create_async_engine(DATABASE_URL, pool_size=10, max_overflow=20)
9async_session_maker = async_sessionmaker(engine, expire_on_commit=False)
10
11class Base(DeclarativeBase): pass
12
13# models.py
14from sqlalchemy.orm import Mapped, mapped_column
15
16class Course(Base):
17 __tablename__ = "courses"
18 id: Mapped[int] = mapped_column(primary_key=True)
19 title: Mapped[str] = mapped_column(index=True)
20 is_published: Mapped[bool] = mapped_column(default=False)Testing
Python
1pip install pytest pytest-asyncio httpx
2
3# tests/test_courses.py
4import pytest
5from httpx import AsyncClient, ASGITransport
6from main import app
7
8@pytest.mark.asyncio
9async def test_list_courses():
10 async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as client:
11 response = await client.get("/courses")
12 assert response.status_code == 200
13 assert isinstance(response.json(), list)Deployment
DOCKERFILE
1# Dockerfile
2FROM python:3.12-slim
3WORKDIR /app
4COPY requirements.txt .
5RUN pip install --no-cache-dir -r requirements.txt
6COPY . .
7RUN adduser --disabled-password appuser && chown -R appuser /app
8USER appuser
9EXPOSE 8000
10CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "4"]