Setup & Installation
Bootstrap FastAPI with uv, configure env, and run with Uvicorn.
Python services use FastAPI — async-first, type-hinted, and OpenAPI-native. It mirrors the Node stack's conventions (/v1/ prefix, Cognito auth, consistent JSON errors) so services stay interchangeable across languages.
Prerequisites
- Python 3.12+ and uv (fast package + venv manager)
- Docker Desktop (for local PostgreSQL / MongoDB)
- AWS Cognito app client configured (see Authentication)
Create a new service
mkdir backend-api && cd backend-api
uv init --package
uv add "fastapi[standard]" uvicorn pydantic-settings
uv add --dev ruff mypy pytest httpxEntry point
# app/main.py
from fastapi import FastAPI
from app.core.config import settings
from app.api.v1 import api_router
from app.middleware.errors import register_exception_handlers
def create_app() -> FastAPI:
app = FastAPI(
title="backend-api",
version="1.0.0",
docs_url="/docs",
openapi_url="/openapi.json",
)
register_exception_handlers(app)
app.include_router(api_router, prefix="/v1")
@app.get("/health")
def health() -> dict[str, str]:
return {"status": "ok", "service": "backend-api"}
return app
app = create_app()Settings (Pydantic)
pydantic-settings is the Python equivalent of validated env config — it parses and type-checks environment variables at startup.
# app/core/config.py
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
model_config = SettingsConfigDict(env_file=".env.local", extra="ignore")
env: str = "development"
port: int = 4000
cors_origin: str = "http://localhost:3000"
# Cognito
cognito_user_pool_id: str
cognito_region: str
cognito_client_id: str
# PostgreSQL (SQLAlchemy)
database_url: str
# MongoDB
mongodb_uri: str | None = None
settings = Settings() # type: ignore[call-arg]Environment variables
cp .env.example .env.localENV=development
PORT=4000
CORS_ORIGIN=http://localhost:3000
# Cognito
COGNITO_USER_POOL_ID=us-east-1_xxxxx
COGNITO_REGION=us-east-1
COGNITO_CLIENT_ID=xxxxxxxx
# PostgreSQL (SQLAlchemy — async driver)
DATABASE_URL=postgresql+asyncpg://user:password@localhost:5432/app
# MongoDB
MONGODB_URI=mongodb://localhost:27017/appLocal dependencies
docker compose up -d postgres mongo
docker compose ps# docker-compose.yml
services:
postgres:
image: postgres:16-alpine
ports: ["5432:5432"]
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: password
POSTGRES_DB: app
mongo:
image: mongo:7
ports: ["27017:27017"]Scripts
Add task shortcuts to pyproject.toml (run via uv run):
# pyproject.toml
[tool.uv]
package = true
[project.scripts]
dev = "app.cli:dev"
[tool.ruff]
line-length = 100
[tool.mypy]
strict = true# Common commands
uv run uvicorn app.main:app --reload --port 4000 # dev
uv run ruff check app/ # lint
uv run mypy app/ # typecheck
uv run pytest # testVerify
uv run uvicorn app.main:app --reload --port 4000
curl http://localhost:4000/health
# {"status":"ok","service":"backend-api"}Interactive OpenAPI docs are generated automatically at http://localhost:4000/docs.
- Health endpoint returns 200.
uv run ruff check app/ && uv run mypy app/ && uv run pytestpass.Database connection succeeds (see SQLAlchemy).
- Authenticated
/v1/request with Cognito token works. - Swagger UI loads at
/docs.