A production-ready Todo API implementing Domain-Driven Design (DDD) and Hexagonal Architecture principles
Features • Architecture • Quick Start • API Documentation • Testing
- Overview
- Features
- Architecture
- Technology Stack
- Project Structure
- Quick Start
- Configuration
- API Documentation
- Design Patterns
- Testing
- Contributing
- License
This project demonstrates a production-grade implementation of a Todo API using FastAPI with Domain-Driven Design (DDD) and Hexagonal Architecture (Ports & Adapters). It showcases best practices for building scalable, maintainable, and testable Python applications.
- 🎯 Domain-Centric: Business logic isolated from infrastructure concerns
- 🔌 Pluggable: Easy to swap implementations (database, message queue, etc.)
- 🧪 Testable: High test coverage with isolated unit tests
- 📈 Scalable: Clean separation enables horizontal scaling
- 🛡️ Maintainable: Clear boundaries reduce coupling and technical debt
- ✅ CQRS Pattern - Separate read and write models
- ✅ Event-Driven Architecture - Domain events for loose coupling
- ✅ Unit of Work Pattern - Transactional consistency
- ✅ Repository Pattern - Data access abstraction
- ✅ Value Objects - Type-safe domain primitives
- ✅ Domain Events - Business event tracking
- ✅ API Versioning - Future-proof API design
- ✅ Exception Handling - Centralized error management
- ✅ Docker Support - Containerized deployment
- ✅ Type Safety - Full type hints with Python 3.12
This project follows the Hexagonal Architecture pattern, organizing code into three main layers:
┌─────────────────────────────────────────────────────────┐
│ Infrastructure Layer │
│ (FastAPI, SQLAlchemy, Event Handlers, External APIs) │
└─────────────────────┬───────────────────────────────────┘
│ Adapters
┌─────────────────────┴───────────────────────────────────┐
│ Application Layer │
│ (Use Cases, DTOs, Interfaces/Ports) │
└─────────────────────┬───────────────────────────────────┘
│ Use Cases
┌─────────────────────┴───────────────────────────────────┐
│ Domain Layer │
│ (Entities, Value Objects, Domain Events, Repositories) │
└─────────────────────────────────────────────────────────┘
🎯 Domain Layer (Core Business Logic)
- Entities and Aggregates
- Value Objects
- Domain Events
- Repository Interfaces
- Business Rules and Invariants
⚙️ Application Layer (Use Cases)
- Command Handlers (Write Operations)
- Query Handlers (Read Operations)
- DTOs (Data Transfer Objects)
- Port Interfaces (UnitOfWork, EventBus)
🔌 Infrastructure Layer (Technical Details)
- FastAPI REST endpoints
- SQLAlchemy ORM models
- Database repositories
- Event bus implementation
- Middleware and exception handlers
| Technology | Purpose | Version |
|---|---|---|
| FastAPI | Web framework | Latest |
| Python | Programming language | 3.12+ |
| PostgreSQL | Database | Latest |
| SQLAlchemy | ORM | Latest |
| Poetry | Dependency management | Latest |
| Docker | Containerization | Latest |
| Pydantic | Data validation | v2.0+ |
src/
├── domain/ # Core business logic
│ ├── entities/ # Domain entities
│ │ └── todo.py # Todo aggregate root
│ ├── value_objects/ # Immutable value types
│ │ ├── todo_id.py # Unique identifier
│ │ ├── todo_status.py # Status enum
│ │ └── priority.py # Priority enum
│ ├── events/ # Domain events
│ │ ├── base.py # Base event
│ │ └── todo_events.py # Todo-specific events
│ ├── repositories/ # Repository interfaces
│ │ └── todo_repository.py
│ └── exceptions.py # Domain exceptions
│
├── application/ # Use cases and DTOs
│ ├── use_cases/
│ │ ├── commands/ # Write operations (CQRS)
│ │ │ ├── create_todo.py
│ │ │ ├── update_todo.py
│ │ │ └── complete_todo.py
│ │ └── queries/ # Read operations (CQRS)
│ │ ├── get_todo.py
│ │ └── list_todos.py
│ ├── dto/ # Data transfer objects
│ │ └── todo_dto.py
│ └── interfaces/ # Port interfaces
│ ├── unit_of_work.py
│ └── event_bus.py
│
├── infrastructure/ # External adapters
│ ├── api/ # FastAPI layer
│ │ └── v1/
│ │ ├── endpoints/
│ │ │ └── todos.py
│ │ ├── schemas.py
│ │ └── dependencies.py
│ ├── persistence/ # Database layer
│ │ └── sqlalchemy/
│ │ ├── models.py
│ │ ├── repositories.py
│ │ ├── read_repositories.py
│ │ ├── unit_of_work.py
│ │ └── database.py
│ └── events/ # Event handling
│ ├── event_bus.py
│ └── handlers.py
│
├── config/ # Configuration
│ └── settings.py
│
└── main.py # Application entry point
- Python 3.12+
- Poetry
- Docker & Docker Compose
- PostgreSQL (or use Docker)
-
Clone the repository
git clone https://github.com/mahdighadiriii/Fastapi-DDD-Hexagonal-Todo.git cd Fastapi-DDD-Hexagonal-Todo -
Install dependencies
poetry install
-
Start PostgreSQL (using Docker)
cd postgres docker-compose up -d -
Configure environment variables
cp .env.example .env # Edit .env with your database credentials -
Run migrations
poetry run alembic upgrade head
-
Start the application
poetry run uvicorn src.main:app --reload
-
Access the API
- API: http://localhost:8000
- Swagger UI: http://localhost:8000/docs
- ReDoc: http://localhost:8000/redoc
If you prefer pip over Poetry:
pip install -r requirements.txt
uvicorn src.main:app --reloadConfiguration is managed through src/config/settings.py using Pydantic settings.
# Database
DATABASE_URL=postgresql://user:password@localhost:5432/todo_db
# Application
APP_NAME=Todo API
VERSION=1.0.0
DEBUG=true
# API
API_V1_PREFIX=/api/v1POST /api/v1/todos
Content-Type: application/json
{
"title": "Complete project documentation",
"description": "Write comprehensive README",
"priority": "HIGH"
}GET /api/v1/todos/{todo_id}GET /api/v1/todos?status=PENDING&priority=HIGH&skip=0&limit=10PUT /api/v1/todos/{todo_id}
Content-Type: application/json
{
"title": "Updated title",
"description": "Updated description",
"priority": "MEDIUM"
}POST /api/v1/todos/{todo_id}/completeDELETE /api/v1/todos/{todo_id}Success Response (201 Created)
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"title": "Complete project documentation",
"description": "Write comprehensive README",
"status": "PENDING",
"priority": "HIGH",
"created_at": "2025-10-26T10:30:00Z",
"updated_at": "2025-10-26T10:30:00Z",
"completed_at": null
}Error Response (404 Not Found)
{
"detail": "Todo not found"
}Separates read and write operations for optimal performance and clarity.
- Commands:
create_todo.py,update_todo.py,complete_todo.py - Queries:
get_todo.py,list_todos.py
Abstracts data access logic from business logic.
# Domain interface
class TodoRepository(ABC):
@abstractmethod
async def add(self, todo: Todo) -> None:
passManages transactions and ensures consistency.
async with uow:
todo = await uow.todos.get(todo_id)
todo.complete()
await uow.commit()Decouples business logic through events.
class TodoCompletedEvent(DomainEvent):
todo_id: TodoId
completed_at: datetimeEncapsulates domain concepts with validation.
@dataclass(frozen=True)
class TodoId:
value: UUID# Run all tests
poetry run pytest
# Run with coverage
poetry run pytest --cov=src --cov-report=html
# Run specific test file
poetry run pytest tests/domain/test_entities.pytests/
├── domain/ # Domain layer tests
├── application/ # Use case tests
├── infrastructure/ # Infrastructure tests
└── conftest.py # Shared fixtures
# Build image
docker build -t fastapi-ddd-todo .
# Run container
docker run -p 8000:8000 fastapi-ddd-tododocker-compose up -d- Connection Pooling: SQLAlchemy manages database connections efficiently
- Async/Await: Non-blocking I/O for better concurrency
- Read Models: Optimized queries for read operations (CQRS)
- Caching: Can be easily integrated at the infrastructure layer
- Indexing: Database indexes on frequently queried fields
- Input validation using Pydantic
- SQL injection prevention via SQLAlchemy ORM
- Environment-based configuration
- CORS middleware configuration
- Exception handling without information leakage
Contributions are welcome! Please follow these steps:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Follow PEP 8 style guide
- Add type hints to all functions
- Write docstrings for public APIs
- Include unit tests for new features
- Update documentation as needed
This project is licensed under the MIT License - see the LICENSE file for details.
Mahdi Ghadiri
- GitHub: @mahdighadiriii
- Project: Fastapi-DDD-Hexagonal-Todo
⭐ If you find this project helpful, please consider giving it a star!
Made with mahdi❤️ using FastAPI and Domain-Driven Design