FastAPI + Python CLAUDE.md Template
March 8, 2026 · View on GitHub
{Project Name}
{One-sentence description of what this project does.} Stack: Python {3.11/3.12}, FastAPI, {SQLAlchemy/Tortoise ORM}, {PostgreSQL/SQLite} Package manager: {poetry / uv / pip}
Commands
# Environment setup
{poetry install} # Install dependencies
{poetry shell} # Activate virtual env
# OR: source .venv/bin/activate # If using venv directly
# Development
{uvicorn app.main:app --reload} # Dev server (port 8000)
# Docs at http://localhost:8000/docs # Swagger UI (auto-generated)
# Testing
{poetry run pytest} # Run all tests
{poetry run pytest tests/path.py} # Single file
{poetry run pytest -k "test_name"} # Single test by name
{poetry run pytest --cov=app} # With coverage
# Code Quality
{poetry run ruff check .} # Linting (Ruff)
{poetry run ruff format .} # Formatting
{poetry run mypy app/} # Type checking
Project Structure
app/
├── main.py # FastAPI app instance, startup, middleware
├── config.py # Settings via pydantic-settings (env vars)
├── dependencies.py # Shared FastAPI dependencies (get_db, get_user)
├── routers/ # Route modules (one per domain)
│ ├── users.py
│ └── items.py
├── models/ # SQLAlchemy/ORM models (DB tables)
├── schemas/ # Pydantic models (request/response shapes)
├── services/ # Business logic (called by routers)
├── repositories/ # Database queries (called by services)
└── utils/ # Pure helpers
migrations/ # Alembic migration files
tests/
├── conftest.py # Fixtures (test client, test DB, factories)
├── test_users.py # Tests mirror router structure
└── factories/ # Test data factories
Endpoint Patterns
- Routers in
app/routers/, included inmain.pywith prefix - Use dependency injection for DB sessions, auth, pagination
- Return Pydantic
response_model— never return ORM objects directly - Status codes: 201 for creation, 204 for deletion, 200 for everything else
# Standard endpoint pattern
from fastapi import APIRouter, Depends, HTTPException, status
from app.schemas.user import UserCreate, UserResponse
from app.services.user_service import UserService
from app.dependencies import get_db
router = APIRouter(prefix="/users", tags=["users"])
@router.post("/", response_model=UserResponse, status_code=status.HTTP_201_CREATED)
async def create_user(data: UserCreate, db=Depends(get_db)):
return await UserService(db).create(data)
@router.get("/{user_id}", response_model=UserResponse)
async def get_user(user_id: int, db=Depends(get_db)):
user = await UserService(db).get_by_id(user_id)
if not user:
raise HTTPException(status_code=404, detail="User not found")
return user
Pydantic Models (Schemas)
{Name}Create— request body for creation (no id){Name}Update— partial update fields (all Optional){Name}Response— API response shape (includes id, timestamps){Name}Base— shared fields inherited by Create/Response- Use
model_config = ConfigDict(from_attributes=True)for ORM conversion
Database Patterns
- ORM: {SQLAlchemy 2.0 async / Tortoise ORM}
- Session: injected via
Depends(get_db)— never create sessions manually - Migrations: {Alembic} — auto-generate with
alembic revision --autogenerate -m "description" - Queries go in
app/repositories/— routers and services never write raw SQL - Transactions: use
async with db.begin():for multi-step operations
Testing with pytest
- Test client:
httpx.AsyncClientwithapp(orTestClientfor sync) - Fixtures in
conftest.py: test DB, authenticated client, sample data - Use factories for test data — not hardcoded dicts
- Mock external services with
unittest.mock.patchorpytest-mock - Name tests:
test_{action}_{expected_result}(e.g.,test_create_user_returns_201)
Code Rules
- Type hints on all function signatures — enforce with mypy
snake_casefor functions/variables,PascalCasefor classes- No
*imports — explicit imports only - Async endpoints by default unless calling sync-only libraries
- Logging via
structlogor stdliblogging— noprint()in app code
Do Not
- Do not put business logic in routers — delegate to services
- Do not return ORM model instances from endpoints — use Pydantic schemas
- Do not edit Alembic migration files after they have been applied
- Do not store secrets in code — use environment variables via
app/config.py - Do not install new dependencies without asking first