Production-ready FastAPI reference implementing a User CRUD service backed by PostgreSQL and SQLAlchemy. The template (root folder name fastapi-reference-arch) showcases a versioned API boundary plus feature modules (api/v1 + modules) and automation hooks for Azure Bicep deployments.
Provide a reference-grade User management API that demonstrates FastAPI best practices, CRUD workflows, and operational readiness for Azure deployments—so new greenfield projects can start from a minimal yet well-structured baseline and layer additional features on top. This README is meant to be enough for a new developer to clone, run locally with Docker Compose, and deploy to Azure with azd.
- Consistent naming conventions plus linting/formatting enforcement (Ruff, Black, isort) keep the codebase uniform.
- FastAPI application using async/await end-to-end with clear boundaries between versioned HTTP contracts (
app/api/v1) and reusable feature internals (app/modules). - Async SQLAlchemy ORM stack (
asyncpg) with Alembic migrations to manage schema changes safely. - Pydantic-powered request/response models that validate inputs and outputs.
- Centralized exception handling maps domain/app faults to consistent HTTP error responses.
- Built-in observability via structured logs plus Application Insights/OpenTelemetry wiring.
- Configurable via
.env, adhering topydantic-settingsand Twelve-Factor conventions. - Docker Compose stack (FastAPI + PostgreSQL) for local development.
- Pytest-based async test suites exercising the full stack through HTTPX clients.
Prerequisites: Docker, Python 3.11+, make.
- Clone the repository:
git clone https://github.com/ppenumatsa1/fastapi-reference-arch.git
cd fastapi-reference-arch- Create Python virtual environment and configure:
python3 -m venv .venv
source .venv/bin/activate # On Windows: .\.venv\Scripts\Activate.ps1
cp .env.example .env- Bring up everything, install deps, run migrations, seed data (idempotent):
make setupThis starts the Docker Compose stack, runs Alembic migrations, and seeds sample Users automatically. Logs: docker compose logs -f api. Stop: make down. Optional direct app run while DB is up: uvicorn app.main:app --reload. To verify the local stack: ./scripts/verify_deployment.sh --env local (defaults to http://localhost:8000).
Environment flags worth tweaking while developing:
APP_DEBUG=truekeeps FastAPI in debug mode.LOG_LEVEL=DEBUGturns on verbose JSON logs.DATABASE_URL/ASYNC_DATABASE_URL(optional) override assembled DSNs if you need a custom connection string.
| Target | Purpose |
|---|---|
make setup |
Installs Python deps, installs pre-commit, applies Alembic migrations, seeds sample User rows. |
make up / make down |
Starts or stops the Docker Compose stack (API + PostgreSQL). |
make up-build |
Rebuilds Docker images (e.g., after dependency changes) before starting the stack. |
make lint |
Runs ruff check via scripts/lint.sh. |
make format |
Runs isort and black through scripts/format.sh. |
make test |
Executes pytest by delegating to scripts/test.sh. |
Run make help to see the latest list as new automation hooks are added.
- Template implementation rules: docs/guides/template-playbook.md
- Error response envelope and examples: docs/guides/error-contract.md
- Observability validation and KQL workflow: docs/guides/observability-validation.md
Prerequisites:
Install these tools first:
Linux (Ubuntu/Debian):
# Azure CLI
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
# Azure Developer CLI
curl -fsSL https://aka.ms/install-azd.sh | bash
# Docker (required by azd package/provision preview for this template)
sudo apt-get update && sudo apt-get install -y docker.io
# PostgreSQL client
sudo apt-get update && sudo apt-get install -y postgresql-client
# Python venv + dependencies (pyproject.toml is the source of truth)
python3 -m venv .venv
source .venv/bin/activate
pip install '.[dev]'Deploy to Azure:
az login # azd reuses these credentials
python3 -m venv .venv # or: py -3 -m venv .venv (Windows)
source .venv/bin/activate # or: .\.venv\Scripts\Activate.ps1 (Windows)
pip install .[dev]
azd env new <env-name>
azd env new <env-name>
azd provision --preview
azd provision --preview
azd up # provision + deploy + run migrations + seed
# subsequent deploys
azd deployNote: Python venv must be activated for azd up and azd deploy - the postdeploy hook runs Alembic migrations which requires Python dependencies.
Also ensure Docker is installed/running before azd provision --preview or azd up.
Verify deployment:
# Azure (uses CONTAINER_APP_FQDN or azd env)
./scripts/verify_deployment.sh --env azure
# Local (defaults to localhost:8000)
./scripts/verify_deployment.sh --env local
# Explicit URL override (any environment)
./scripts/verify_deployment.sh --base-url https://my-app.azurecontainerapps.ioRuns automated tests to verify health, DB reads, and writes. The script defaults to local mode; Azure mode requires CONTAINER_APP_FQDN (or an azd env with that value) unless --base-url is provided.
Config resolution behavior:
--base-urlor--env azuredefaults to telemetry-check mode on.- Local target defaults to telemetry-check mode off.
Note: On first run, azd up will interactively prompt you to:
- Select an Azure subscription
- Choose an existing resource group or create a new one
- Pick an Azure region (e.g., Central US)
For infrastructure internals (Bicep modules, azd hooks, migration scripts, and hardening notes), see infra/README.md and infra/bicep/README.md.
See docs/design/projectstructure.md for the full directory tree and naming conventions. Additional documentation (PRD, architecture notes, tech stack, user flows) lives under docs/design/.
- Local (password mode): Docker Compose supplies
user_user/user_passfor the bundled PostgreSQL container. Override via.envif needed. - Azure (Microsoft Entra mode): The app uses the Container Apps user-assigned managed identity for PostgreSQL login. Runtime acquires short-lived Entra access tokens and does not rely on
DATABASE_PASSWORD.
- Azure: postdeploy hook runs migrations and seeds on every
azd deploy. - Azure migration hook uses Entra token auth (
DB_AUTH_MODE=aad) and the configured PostgreSQL Entra admin identity. - Local/CI:
bash ./infra/scripts/run_migrations.sh(password mode for local Docker defaults, or Entra token mode whenDB_AUTH_MODE=aad). - Local defaults: host
localhost, port5432, useruser_user, passworduser_pass, dbuser_db,APP_ENV=development,LOG_LEVEL=INFO. - Azure env (Entra mode):
DB_AUTH_MODE=aad,DATABASE_HOST=<postgres-fqdn>,DATABASE_NAME=postgres,DATABASE_USER=<managed-identity-name>,AZURE_CLIENT_ID=<uami-client-id>.
Application Insights is enabled when APPLICATIONINSIGHTS_CONNECTION_STRING is set. OpenTelemetry captures request spans, dependency spans, and traces.
Observability references:
- Instrumentation details: docs/design/instrument-flow.md
- Kusto queries and suite runner: scripts/kusto
Run all core checks:
./scripts/kusto/run-observability-suite.shRun end-to-end timeline query directly:
az monitor app-insights query \
--app <application-id> \
--analytics-query "$(cat scripts/kusto/end-to-end-flow-by-operation.kql)"This project is licensed under the MIT License - see the LICENSE file for details.