Python fastapi ddd skill
Skill iktakahiro/python-fastapi-ddd-skill/skills/python-fastapi-ddd-skill
A practical template for Building AI Agent Skills with Python, FastAPI, and Domain-Driven Design (DDD).
npx -y skills add iktakahiro/python-fastapi-ddd-skill --skill python-fastapi-ddd-skillAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 3 stars3 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Guides FastAPI backend design using Domain-Driven Design (DDD) and Onion Architecture in Python. Use when structuring a FastAPI app (routes/handlers, Pydantic schemas, Depends-based DI), modeling domain Entities/Value Objects, defining repository interfaces, implementing SQLAlchemy infrastructure adapters, or writing use cases, based on the dddpy reference.
The file declares its own license as Apache-2.0. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
5.6 KB, as published. Nobody here has run it
FastAPI + Python DDD & Onion Architecture Design Guide
Guides FastAPI backend design using DDD principles and Onion Architecture, based on the dddpy reference implementation (FastAPI + SQLAlchemy + Python 3.13+).
Architecture Overview
Four concentric layers with dependencies pointing inward:
Presentation → UseCase → Infrastructure → Domain (innermost)
Key rule: Inner layers never depend on outer layers. The Domain layer has zero external dependencies.
| Layer | Responsibility | Examples |
|---|---|---|
| Domain | Core business logic, no framework deps | Entities, Value Objects, Repository interfaces, Exceptions |
| Infrastructure | External integrations | DB repos, DTOs, DI config, SQLAlchemy models |
| UseCase | Application workflows | One class per use case with execute() |
| Presentation | HTTP API surface | FastAPI routes, Pydantic schemas, error messages |
For detailed architecture guide: See ARCHITECTURE.md
Directory Structure
project/
├── main.py
├── app/
│ ├── domain/
│ │ └── {aggregate}/
│ │ ├── entities/
│ │ ├── value_objects/
│ │ ├── repositories/
│ │ └── exceptions/
│ ├── infrastructure/
│ │ ├── di/
│ │ │ └── injection.py
│ │ └── sqlite/
│ │ └── {aggregate}/
│ │ ├── {aggregate}_dto.py
│ │ └── {aggregate}_repository.py
│ ├── usecase/
│ │ └── {aggregate}/
│ │ └── {action}_{aggregate}_usecase.py
│ └── presentation/
│ └── api/
│ └── {aggregate}/
│ ├── handlers/
│ ├── schemas/
│ └── error_messages/
└── tests/
Quick Reference
1. Entity
Entities have unique identifiers, mutable state, and encapsulated business logic. Equality is based on identity, not attribute values.
class Todo:
def __init__(self, id: TodoId, title: TodoTitle, status: TodoStatus = TodoStatus.NOT_STARTED):
self._id = id
self._title = title
self._status = status
def __eq__(self, obj: object) -> bool:
if isinstance(obj, Todo):
return self.id == obj.id
return False
def start(self) -> None:
self._status = TodoStatus.IN_PROGRESS
@staticmethod
def create(title: TodoTitle) -> "Todo":
return Todo(TodoId.generate(), title)
Detailed guide: See ENTITIES.md
2. Value Object
Immutable objects defined by their values, not identity. Use @dataclass(frozen=True) with validation in __post_init__.
@dataclass(frozen=True)
class TodoTitle:
value: str
def __post_init__(self):
if not self.value:
raise ValueError("Title is required")
if len(self.value) > 100:
raise ValueError("Title must be 100 characters or less")
Detailed guide: See VALUE_OBJECTS.md
3. Repository Interface
Define abstract interfaces in the Domain layer. Infrastructure implements them.
class TodoRepository(ABC):
@abstractmethod
def save(self, todo: Todo) -> None: ...
@abstractmethod
def find_by_id(self, todo_id: TodoId) -> Optional[Todo]: ...
@abstractmethod
def find_all(self) -> List[Todo]: ...
@abstractmethod
def delete(self, todo_id: TodoId) -> None: ...
Detailed guide: See REPOSITORIES.md
4. UseCase
One class per use case. Abstract interface + concrete implementation + factory function.
class CreateTodoUseCase(ABC):
@abstractmethod
def execute(self, title: TodoTitle) -> Todo: ...
class CreateTodoUseCaseImpl(CreateTodoUseCase):
def __init__(self, todo_repository: TodoRepository):
self.todo_repository = todo_repository
def execute(self, title: TodoTitle) -> Todo:
todo = Todo.create(title=title)
self.todo_repository.save(todo)
return todo
def new_create_todo_usecase(repo: TodoRepository) -> CreateTodoUseCase:
return CreateTodoUseCaseImpl(repo)
Detailed guide: See USECASES.md
Best Practices
- Keep Domain Layer Pure: No framework imports (no FastAPI, no SQLAlchemy) in domain code
- Use DTOs at Layer Boundaries: Convert between domain entities and infrastructure models via
to_entity()/from_entity()methods - Dependency Injection: Use FastAPI's
Depends()to wire session → repository → usecase → handler - One UseCase = One Responsibility: Each UseCase has exactly one public
executemethod - Validate in Value Objects: Business rules live in
__post_init__of frozen dataclasses - Domain Exceptions: Create specific exception classes for business rule violations (e.g.,
TodoNotFoundError,TodoAlreadyCompletedError) - Factory Functions: Expose
new_*factory functions for creating implementations, keeping concrete classes as implementation details