Section 1: FastAPI fundamentals
Project setup and the first endpoints
Create the project and install dependencies with uv:
uv init taskboard --package
cd taskboard
uv add "fastapi[standard]" "sqlalchemy[asyncio]" asyncpg alembic pydantic-settings
uv add --dev pytest httpx
The fastapi[standard] extra includes Uvicorn, the ASGI server, and the fastapi command line tool.
Project layout
src/taskboard/
main.py app creation
config.py settings
db.py engine and session
models/ SQLAlchemy models
schemas/ Pydantic models
routers/ one module per resource
services/ business logic
tests/
Separating schemas (what the API accepts and returns) from models (how data is stored) feels like duplication at first. It pays off quickly: you can change the database without breaking the API contract, and you never leak internal fields such as password hashes by accident.
The app
from fastapi import FastAPI
from taskboard.routers import health, projects
app = FastAPI(title="Taskboard API", version="0.1.0")
app.include_router(health.router)
app.include_router(projects.router, prefix="/projects", tags=["projects"])
A health router is a good first endpoint:
from fastapi import APIRouter
router = APIRouter()
@router.get("/health")
async def health() -> dict[str, str]:
return {"status": "ok"}
Run the development server with auto reload:
uv run fastapi dev src/taskboard/main.py
Open /docs in the browser. FastAPI generated interactive Swagger UI documentation from your code. /openapi.json is the machine readable document behind it.
Settings
Configuration comes from environment variables, validated by pydantic-settings:
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
model_config = SettingsConfigDict(env_file=".env")
database_url: str
jwt_secret: str
debug: bool = False
settings = Settings()
If a required variable is missing, the app fails at startup with a clear message instead of failing later on the first request. Keep a .env.example in the repository and the real .env out of it.
A first resource with fake data
Add a projects router with GET /projects returning a hard coded list, and check it in /docs. In the next lesson we replace the dicts with Pydantic models.