Python FastAPI DDD
Use this skill to build or review Python FastAPI services shaped around Domain-Driven Design and Onion Architecture. It combines the upstream architecture, presentation, testing, and tooling skills into one Codex skill.
The source material is based on Takahiro Ikeuchi's python-fastapi-ddd-skill and the dddpy reference implementation. See SOURCES.md for upstream links and the copied revision.
Reference Map
Load the narrowest reference that matches the task:
- ARCHITECTURE.md: layer boundaries, directory structure, request flow, DI chain, adding a new aggregate.
- VALUE_OBJECTS.md: frozen dataclass value objects, validation, IDs, enums, composite values.
- ENTITIES.md: identity-based equality, encapsulation, state transitions, factories.
- REPOSITORIES.md: domain repository interfaces, SQLAlchemy adapters, DTO mapping, FastAPI dependency wiring.
- USECASES.md: one workflow per use case,
execute(), factories, domain exception flow.
- PRESENTATION.md: route handlers, Pydantic request/response schemas, error mapping, OpenAPI responses.
- TESTING.md: pytest patterns for value objects, entities, and use cases with repository mocks.
- TOOLING.md: uv, ruff, mypy, pytest, Makefile, CI, FastAPI lifespan, SQLAlchemy bootstrap.
Core Workflow
- Inspect the existing project first:
pyproject.toml, package layout, tests, dependency policy, and agent instructions.
- Pick the relevant layer before editing. Keep changes close to that layer and do not leak outer-framework concerns inward.
- Model business concepts in the Domain layer first: Value Objects for validated values, Entities for identity and state, domain exceptions for business failures, and repository interfaces for persistence contracts.
- Add UseCases as application workflows. Use one class per use case with one public
execute() method. Depend on domain repository interfaces, not concrete SQLAlchemy adapters.
- Put FastAPI, Pydantic, SQLAlchemy sessions, DTOs, and dependency wiring outside the Domain layer.
- Add focused tests for changed behavior. Prefer pure domain tests without mocks and use case tests with
Mock(spec=RepositoryInterface).
- Run the repository's configured format, lint, type, and test commands before reporting completion.
Layer Rules
Dependencies point inward:
Presentation -> UseCase -> Domain
Infrastructure -> Domain
Composition/DI -> Presentation, UseCase, Infrastructure
- Domain has zero FastAPI, Pydantic, SQLAlchemy, settings, logging, or HTTP imports.
- UseCase coordinates workflows and transactions at the application boundary; it does not know about HTTP requests or ORM models.
- Infrastructure implements domain ports such as repositories and converts between domain objects and persistence DTOs.
- Presentation parses HTTP input, constructs Value Objects, calls UseCases, maps domain exceptions to HTTP responses, and converts Entities to response schemas.
- Composition roots wire concrete dependencies with FastAPI
Depends() or project-local DI helpers.
Dependency Policy
Honor the target repository's dependency rules. If FastAPI, SQLAlchemy, Pydantic, pytest, ruff, mypy, or uv are not installed yet, do not add them unless the user asks. You can still create domain/use case structure, tests that use existing tools, or documentation that marks future framework integration points.
Naming And Structure
Use project conventions when they already exist. For greenfield DDD code, use a clear aggregate-centered layout:
app/
domain/{aggregate}/
entities/
value_objects/
repositories/
exceptions/
usecase/{aggregate}/
infrastructure/{database_or_adapter}/{aggregate}/
presentation/api/{aggregate}/
handlers/
schemas/
error_messages/
In src/ layout repositories, put the application package under src/ and keep tests under tests/.
Implementation Defaults
- Value Objects:
@dataclass(frozen=True), validate in __post_init__, expose primitive values explicitly.
- Entities: compare by ID, keep state private, expose behavior methods for valid state transitions.
- Repositories: define abstract interfaces in Domain; return Domain objects, not ORM rows.
- DTOs/adapters: convert through
to_entity() and from_entity() or equivalent named methods.
- UseCases: accept Value Objects and domain primitives, return Domain objects or explicit result types.
- Presentation schemas: separate request and response models; use
from_entity() for responses.
- Errors: raise domain-specific exceptions inside Domain/UseCase and map them to HTTP status codes only in Presentation.
- Tests: assert invariants, transitions, and repository interactions at the lowest meaningful layer.
Common Mistakes
- Importing FastAPI, Pydantic, SQLAlchemy, or settings into Domain.
- Treating Pydantic models or ORM rows as Entities.
- Putting validation only in request schemas when it represents business rules.
- Injecting concrete repositories into UseCases instead of repository interfaces.
- Creating generic service classes that hide multiple workflows behind one broad method set.
- Testing use cases with unspecced mocks that allow misspelled repository methods.
1---2name: python-fast-api-ddd3description: Use when designing, implementing, reviewing, or testing Python FastAPI backends that follow Domain-Driven Design, Onion/Clean Architecture, repository and use case patterns, SQLAlchemy infrastructure adapters, Pydantic presentation schemas, pytest unit tests, or uv/ruff/mypy/pytest tooling.4---56# Python FastAPI DDD78Use this skill to build or review Python FastAPI services shaped around Domain-Driven Design and Onion Architecture. It combines the upstream architecture, presentation, testing, and tooling skills into one Codex skill.910The source material is based on Takahiro Ikeuchi's `python-fastapi-ddd-skill` and the `dddpy` reference implementation. See [SOURCES.md](references/SOURCES.md) for upstream links and the copied revision.1112## Reference Map1314Load the narrowest reference that matches the task:1516- [ARCHITECTURE.md](references/ARCHITECTURE.md): layer boundaries, directory structure, request flow, DI chain, adding a new aggregate.17- [VALUE_OBJECTS.md](references/VALUE_OBJECTS.md): frozen dataclass value objects, validation, IDs, enums, composite values.18- [ENTITIES.md](references/ENTITIES.md): identity-based equality, encapsulation, state transitions, factories.19- [REPOSITORIES.md](references/REPOSITORIES.md): domain repository interfaces, SQLAlchemy adapters, DTO mapping, FastAPI dependency wiring.20- [USECASES.md](references/USECASES.md): one workflow per use case, `execute()`, factories, domain exception flow.21- [PRESENTATION.md](references/PRESENTATION.md): route handlers, Pydantic request/response schemas, error mapping, OpenAPI responses.22- [TESTING.md](references/TESTING.md): pytest patterns for value objects, entities, and use cases with repository mocks.23- [TOOLING.md](references/TOOLING.md): uv, ruff, mypy, pytest, Makefile, CI, FastAPI lifespan, SQLAlchemy bootstrap.2425## Core Workflow26271. Inspect the existing project first: `pyproject.toml`, package layout, tests, dependency policy, and agent instructions.282. Pick the relevant layer before editing. Keep changes close to that layer and do not leak outer-framework concerns inward.293. Model business concepts in the Domain layer first: Value Objects for validated values, Entities for identity and state, domain exceptions for business failures, and repository interfaces for persistence contracts.304. Add UseCases as application workflows. Use one class per use case with one public `execute()` method. Depend on domain repository interfaces, not concrete SQLAlchemy adapters.315. Put FastAPI, Pydantic, SQLAlchemy sessions, DTOs, and dependency wiring outside the Domain layer.326. Add focused tests for changed behavior. Prefer pure domain tests without mocks and use case tests with `Mock(spec=RepositoryInterface)`.337. Run the repository's configured format, lint, type, and test commands before reporting completion.3435## Layer Rules3637Dependencies point inward:3839```text40Presentation -> UseCase -> Domain41Infrastructure -> Domain42Composition/DI -> Presentation, UseCase, Infrastructure43```4445- Domain has zero FastAPI, Pydantic, SQLAlchemy, settings, logging, or HTTP imports.46- UseCase coordinates workflows and transactions at the application boundary; it does not know about HTTP requests or ORM models.47- Infrastructure implements domain ports such as repositories and converts between domain objects and persistence DTOs.48- Presentation parses HTTP input, constructs Value Objects, calls UseCases, maps domain exceptions to HTTP responses, and converts Entities to response schemas.49- Composition roots wire concrete dependencies with FastAPI `Depends()` or project-local DI helpers.5051## Dependency Policy5253Honor the target repository's dependency rules. If FastAPI, SQLAlchemy, Pydantic, pytest, ruff, mypy, or uv are not installed yet, do not add them unless the user asks. You can still create domain/use case structure, tests that use existing tools, or documentation that marks future framework integration points.5455## Naming And Structure5657Use project conventions when they already exist. For greenfield DDD code, use a clear aggregate-centered layout:5859```text60app/61 domain/{aggregate}/62 entities/63 value_objects/64 repositories/65 exceptions/66 usecase/{aggregate}/67 infrastructure/{database_or_adapter}/{aggregate}/68 presentation/api/{aggregate}/69 handlers/70 schemas/71 error_messages/72```7374In `src/` layout repositories, put the application package under `src/` and keep tests under `tests/`.7576## Implementation Defaults7778- Value Objects: `@dataclass(frozen=True)`, validate in `__post_init__`, expose primitive values explicitly.79- Entities: compare by ID, keep state private, expose behavior methods for valid state transitions.80- Repositories: define abstract interfaces in Domain; return Domain objects, not ORM rows.81- DTOs/adapters: convert through `to_entity()` and `from_entity()` or equivalent named methods.82- UseCases: accept Value Objects and domain primitives, return Domain objects or explicit result types.83- Presentation schemas: separate request and response models; use `from_entity()` for responses.84- Errors: raise domain-specific exceptions inside Domain/UseCase and map them to HTTP status codes only in Presentation.85- Tests: assert invariants, transitions, and repository interactions at the lowest meaningful layer.8687## Common Mistakes8889- Importing FastAPI, Pydantic, SQLAlchemy, or settings into Domain.90- Treating Pydantic models or ORM rows as Entities.91- Putting validation only in request schemas when it represents business rules.92- Injecting concrete repositories into UseCases instead of repository interfaces.93- Creating generic service classes that hide multiple workflows behind one broad method set.94- Testing use cases with unspecced mocks that allow misspelled repository methods.