Skip to content

Repository files navigation

ddd-fast-api

Project status: planning  Python 3.12+  GitHub stars  GitHub forks  GitHub issues  License: MIT

An open-source, production-oriented FastAPI service template inspired by Ardan Labs Service.

The project translates Ardan's emphasis on explicit boundaries, small mental models, operational completeness, and domain-oriented design into idiomatic Python. It is intended to be a starting point, not another framework layered on top of FastAPI.

Project status: early scaffold with a working runtime and operations baseline. The reference business domain and template-generation experience are still in progress; roadmap items are checked only when the corresponding repository artifacts and validation exist.

Contents

Why this project exists

Many FastAPI examples demonstrate routing and database access but stop before the concerns that make a service maintainable in production. This template aims to provide a coherent reference for:

  • keeping business rules independent of FastAPI and persistence;
  • organizing a modular service around domain language;
  • defining explicit transaction and dependency boundaries;
  • testing domain behavior without HTTP, PostgreSQL, or network access;
  • shipping local and Kubernetes workflows from the same repository;
  • providing logs, metrics, traces, health signals, security, and CI by default;
  • generating new domain seams without generating business rules.

The initial reference domain will model inventory and catalog management. A separate identity capability will demonstrate local account signup, user management, RBAC, and a replaceable external OIDC adapter.

Design principles

  1. Pragmatic DDD — use entities, value objects, aggregates, and domain events only when they clarify real business rules.
  2. Dependencies point inward — domain code has no FastAPI, Pydantic, SQLAlchemy, or infrastructure imports.
  3. Frameworks stay at the edges — FastAPI is the HTTP adapter, not the application architecture.
  4. Explicit mapping — transport schemas, domain models, and persistence models evolve independently.
  5. Use-case transactions — the application layer owns commit and rollback; repositories never commit independently.
  6. Operations are architecture — containers, Kubernetes, migrations, telemetry, and CI are maintained alongside the service.
  7. Minimal dependencies — add libraries for demonstrated needs, not for hypothetical flexibility.

Target architecture

The architecture is easiest to read as four focused views rather than one dense diagram:

System context

System context showing the client, API, database, identity provider, and external services

See the editable source at docs/architecture-context.mmd.

Container architecture

Container architecture showing the five service layers and their dependencies

See the editable source at docs/architecture.mmd.

Request lifecycle

Request lifecycle sequence from HTTP entrypoint through application, domain, and persistence

See the editable source at docs/request-lifecycle.mmd.

Deployment flow

Deployment flow showing validation, image build, migration, and rollout

See the editable source at docs/deployment-flow.mmd.

The composition root is the only place that knows every concrete adapter. Domain modules are mirrored across layers so a feature remains traceable from HTTP input to business behavior and storage.

The current repository shape is:

ddd-fast-api/
├── .github/workflows/       # Quality, security, and delivery checks
├── .husky/                  # Local commit hooks
├── alembic/                 # Database migrations
├── docs/                    # ADRs, architecture, diagrams, and validation
├── src/ddd_fast_api/
│   ├── entrypoints/http/     # FastAPI routes, schemas, dependencies, telemetry
│   ├── application/          # Catalog and identity use cases
│   ├── domain/               # Catalog and identity entities, rules, and ports
│   ├── infrastructure/
│   │   ├── persistence/      # SQLAlchemy models, mappers, repositories, UoW
│   │   └── http_client.py    # Timeout and bounded-retry HTTP adapter
│   ├── foundation/           # Settings, errors, logging, auth, telemetry
│   └── bootstrap.py           # Composition root and application lifecycle
├── tests/
│   ├── unit/
│   ├── integration/
│   └── architecture/
├── zarf/                    # Compose, Helm, Kustomize, and Kind assets
├── main.py                  # Compatibility application entrypoint
├── package.json              # Husky setup
├── pyproject.toml
├── uv.lock
└── Makefile

Pydantic's role

Pydantic will validate and serialize data at system boundaries:

  • API request and response schemas;
  • OpenAPI generation;
  • application configuration through pydantic-settings;
  • messages exchanged with external systems.

Core domain entities and value objects remain plain Python types or dataclasses. Explicit mappers translate between Pydantic schemas, domain models, and SQLAlchemy models. This separation keeps business behavior testable and allows the HTTP, domain, and persistence representations to evolve independently.

Planned capabilities

The template targets Python equivalents for the production capabilities shown by Ardan Labs Service:

  • FastAPI and Starlette routing, lifespan, dependencies, and middleware;
  • PostgreSQL with SQLAlchemy 2 async, asyncpg, and Alembic;
  • CRUD use cases, filtering, ordering, pagination, and stable errors;
  • local accounts, JWT/OIDC authentication, RBAC, and object-level policies;
  • structured logging, OpenTelemetry, Prometheus-compatible metrics, Tempo, and Grafana;
  • pytest-based unit, integration, contract, property, architecture, and smoke tests;
  • locked dependencies with an optional wheelhouse for offline builds;
  • multi-stage Docker images and Docker Compose for local development;
  • Helm/Kustomize-based Kubernetes environments, a local Kind registry workflow, and a separate migration Job;
  • GitHub Actions as the default CI/CD implementation, with CircleCI documented as an alternative;
  • OpenAPI, MkDocs, and source-reference documentation;
  • a project template and domain-scaffolding command.

A capability counts as implemented only when code or configuration, automated tests, user documentation, and a passing CI check all exist.

Repository status

Currently present:

  • Git repository and main branch;
  • Python project metadata, runtime dependencies, and development tooling baseline;
  • a uv lockfile for the current executable scaffold;
  • Python 3.12+ support decision;
  • typed runtime settings with an .env.example bootstrap;
  • a foundation error model and FastAPI exception handler registration;
  • structured JSON logging wired into the bootstrap path;
  • SQLAlchemy async and Alembic persistence scaffolding;
  • a SQLAlchemy catalog ORM model and repository adapter scaffold;
  • a SQLAlchemy-backed catalog unit-of-work seam for application-owned catalog transaction boundaries;
  • an initial Alembic revision for the catalog table;
  • bootstrap-managed shared persistence resources for the SQLAlchemy path;
  • src/ddd_fast_api layer packages for entrypoints, application, domain, infrastructure, and foundation;
  • the first plain-Python catalog domain skeleton with invariant tests;
  • the first plain-Python identity domain skeleton with invariant tests;
  • the first identity repository port and application lookup use case;
  • a sample identity HTTP endpoint with structured 400/404 responses;
  • a SQLAlchemy identity ORM model and repository adapter scaffold;
  • the first application-layer catalog use case and repository port;
  • a sample catalog HTTP endpoint wired through the application layer;
  • catalog list filtering, ordering, and pagination through typed domain and HTTP query models;
  • a sample catalog detail endpoint with structured 400/404 responses;
  • a settings-driven seam for choosing the catalog adapter (defaulting to memory);
  • a settings-driven seam for choosing the identity adapter (defaulting to memory);
  • an initial architecture test that guards domain-layer imports;
  • expanded architecture tests that guard domain, application, and foundation layer boundaries;
  • a minimal FastAPI app factory with / and /health routes;
  • replaceable bearer authentication and permission dependency examples;
  • liveness, readiness, startup, request telemetry, and Prometheus metrics routes;
  • a shared timeout- and bounded-retry outbound HTTP adapter;
  • an initial unit test covering the scaffold entrypoints;
  • a GitHub Actions quality workflow definition for tests, Ruff, and mypy;
  • optional Husky git hooks for commit-time formatting, linting, and conventional commit validation;
  • explicit Pydantic boundary schemas for the scaffold metadata endpoints;
  • repository ignore rules;
  • this project overview;
  • MIT licensing.

Not yet present:

  • business-domain implementation beyond the scaffold metadata endpoints;
  • contract and smoke test layers.

Getting started

The repository contains an executable foundation and production-runtime baseline. You can install the dependencies, prepare the environment file, run the app, and inspect the package layout that future domain work will build on:

git clone https://github.com/owezzy/ddd-fast-api.git
cd ddd-fast-api
uv sync --group dev
cp .env.example .env
uv run python main.py

The local server starts on http://127.0.0.1:8000 and currently exposes:

  • GET / — scaffold metadata
  • GET /health — simple health check
  • GET /catalog/items — sample catalog items via the application layer with optional filtering, ordering, and pagination query parameters
  • GET /catalog/items/{sku} — one sample catalog item by SKU
  • GET /identity/users/{email} — one sample user account by email

Current runtime configuration lives in src/ddd_fast_api/foundation/settings.py and is populated from .env using the DDD_FAST_API_ prefix.

The catalog endpoints currently default to the in-memory adapter. The SQLAlchemy adapter can be selected by setting DDD_FAST_API_CATALOG_REPOSITORY_BACKEND to sqlalchemy. When selected, the app now reuses bootstrap-managed persistence resources for the default configuration and falls back to an isolated engine in override-driven tests. Catalog application use cases now execute through an explicit catalog unit-of-work seam instead of depending directly on raw repository instances.

If you prefer stable task-style commands over raw uv invocations, the current scaffold also provides:

make sync
make run
make test
make lint
make type-check

Optional contributor git tooling is also available:

make hooks
make commit
  • make hooks installs the local Husky git hooks from package.json and configures Git to use the Commitizen dialog for manual git commit commands.
  • The pre-commit hook runs make format and make lint before each commit.
  • The commit-msg hook validates messages with Commitizen's conventional commit rules.
  • make commit opens an interactive Commitizen prompt via uv run cz commit.

Read these sections next:

  1. Design principles for the rules every contribution must preserve.
  2. Target architecture for layer responsibilities and dependency direction.
  3. Pydantic's role for the boundary-versus-domain decision.
  4. Repository status for an accurate implementation snapshot.
  5. Delivery roadmap for the planned build sequence.

Runtime capability details are documented in docs/production-runtime.md.

Development requirements for the current scaffold are:

  • Git
  • Python 3.12+
  • uv

Optional local commit-hook workflow requirements:

  • Node.js
  • npm

CI tests Python 3.12, 3.13, and 3.14. Docker, Docker Compose, Kind, kubectl, Helm, and Kustomize are requirements for the operations workflows.

The root main.py is now a compatibility bootstrap that starts the packaged application. It exists to keep the first runnable command simple while the project transitions fully into the src/ddd_fast_api layout.

Validation

The end-to-end validation path is documented in docs/validation.md. It covers fresh-clone quality checks, live application smoke checks, Compose database startup, and Helm and Kustomize rendering. The CI delivery job runs configuration and packaging checks automatically; Docker, Kind, and live HTTP checks are run locally when those tools are available.

Delivery roadmap

  • Define architecture, feature parity, and dependency rules.
  • Initialize and publish the repository.
  • Establish Python 3.12+ and MIT license decisions.
  • Foundation: package layout, configuration, lifecycle, errors, logging, dependency rules, quality tools, and architecture tests.
  • Reference slice: inventory/catalog contract, domain behavior, PostgreSQL adapter, migrations, and tests.
  • Production runtime: account management, authentication, authorization, telemetry, health checks, and resilient HTTP clients.
  • Operations: Docker, Compose, migration jobs, Helm/Kustomize Kubernetes packaging, CI/CD, and security scanning.
  • Template experience: project generation, domain scaffolding, documentation, examples, and releases.
  • Validation: validate a fresh clone, run the documented workflows, deploy to local and Kubernetes environments, and complete a newcomer review.

Contributing

See CONTRIBUTING.md for the current contributor workflow, local quality gates, and commit conventions.

The intended domain generator contract is documented in docs/scaffolding.md so future implementation work has a stable architectural target.

Architecture decisions that are expensive to reverse, surprising without context, and based on a real trade-off should be recorded under docs/adr/.

License

Distributed under the MIT License.

Acknowledgments

  • Ardan Labs Service for the production service architecture and operational-completeness inspiration.
  • FastAPI and Pydantic for Python's typed API boundary tools.
  • Architecture Patterns with Python by Harry Percival and Bob Gregory for practical ports, adapters, repositories, and units of work in Python.

About

No description, website, or topics provided.

Resources

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages