Hexagonal Architecture Generator for FastAPI
Generate FastAPI CRUD modules following hexagonal (ports & adapters) architecture principles.
Features
- Complete CRUD Generation: Generate domain models, DTOs, repositories, use cases, schemas, and API routes
- Hexagonal Architecture: Enforces proper layer separation (Domain, Application, Infrastructure)
- SQLAlchemy 2.0: Uses modern Mapped types and select() statements
- Pydantic V2: Includes Field validations and OpenAPI documentation
- Unit of Work Pattern: Transaction management abstraction
- Architecture Validation: Check compliance with hexagonal principles
Quick Start
Installation
pip install -e .
CLI Usage
# Generate a CRUD module (always written under ./generated_project)
python code_generator.py crud School
# Generate CRUD with specific actions
python code_generator.py crud Product --actions create list retrieve
# Copy a built-in application
python code_generator.py builtin user
# Verbose output
python code_generator.py crud Order -v
Generated Structure
generated_project/
└── src/
└── school/
├── domain/ # Business logic & entities
│ ├── entities.py # Domain entity + Create/Update DTOs (dataclasses)
│ ├── exceptions.py # Domain-level exceptions
│ ├── repository.py # Repository interface (port)
│ └── unit_of_work.py # Transaction interface (port)
├── application/ # Use cases & orchestration
│ ├── schemas.py # Pydantic schemas (API contracts)
│ └── use_cases/ # One class per CRUD action
│ ├── create.py
│ ├── retrieve.py
│ ├── list.py
│ ├── update.py
│ └── delete.py
└── infrastructure/ # External adapters
├── models.py # SQLAlchemy ORM model
├── database.py # Repository implementation
├── unit_of_work.py # SQLAlchemy UoW implementation
├── web.py # FastAPI routes
└── exception_handlers.py # Maps domain exceptions to HTTP responses
Architecture Principles
Domain Layer (Core)
- Pure business logic
- No external dependencies (no Pydantic, FastAPI, SQLAlchemy in DTOs)
- Defines interfaces (ports) for infrastructure
- Uses simple dataclasses for DTOs
Application Layer (Use Cases)
- Orchestrates domain logic
- Defines API contracts (Pydantic schemas)
- Maps between layers
- Depends only on Domain layer
Infrastructure Layer (Adapters)
- Implements domain interfaces
- Handles external concerns (database, web, etc.)
- Depends on Domain and Application layers
- Injects dependencies via FastAPI
Example: Generated Code
Domain DTO (Pure Python)
from dataclasses import dataclass
@dataclass
class CreateSchoolDTO:
name: str
address: str
principal_name: str
student_capacity: int
Domain Model (SQLAlchemy 2.0)
from sqlalchemy.orm import Mapped, mapped_column
class School(Base):
__tablename__ = "schools"
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str] = mapped_column(String(200))
address: Mapped[str]
principal_name: Mapped[str]
student_capacity: Mapped[int]
Application Schema (Pydantic V2)
from pydantic import BaseModel, Field
class CreateSchoolRequest(BaseModel):
name: str = Field(..., min_length=1, max_length=200)
address: str = Field(..., min_length=1)
principal_name: str = Field(..., min_length=1)
student_capacity: int = Field(..., ge=0)
Use Case (Application Layer)
The repository (port) and the UnitOfWork (transaction boundary) are injected
separately — both FastAPI dependencies resolve to the same AsyncSession per
request, so a unit_of_work.commit() after a repository call commits that
call's changes:
class CreateUseCase:
def __init__(self, *, unit_of_work: UnitOfWork, school_repository: SchoolRepository):
self.unit_of_work = unit_of_work
self.school_repository = school_repository
async def execute(self, *, data: CreateSchoolData) -> School:
school = await self.school_repository.create(data=data)
await self.unit_of_work.commit()
return school
Design Patterns Used
- Hexagonal Architecture: Clean separation of concerns
- Repository Pattern: Data access abstraction
- Unit of Work: Transaction management
- Dependency Injection: FastAPI Depends()
- Mapper Pattern: Layer-to-layer conversion
- Factory Pattern: Generator creation
Architecture Validation
The generator includes a validator that checks:
- Domain doesn't import Application/Infrastructure
- Application doesn't import Infrastructure
- No SQLAlchemy Session in use cases
- Proper use of DTOs in domain layer
- Dependency inversion respected
from hexagon_generator.utils import ArchitectureValidator
validator = ArchitectureValidator(Path("generated_project"))
result = validator.validate_module("school")
Docker Usage
# Build image
docker build -f generator.dockerfile -t hexagon-generator:latest .
# Run generator
docker run --name hexagon-generator -p 8069:8069 \
-v "${PWD}:/mounted_project" \
hexagon-generator:latest
Project Structure
.
├── code_generator.py # CLI entry point
├── hexagon_generator/ # Core generator
│ ├── core/ # Generation logic
│ ├── templates/ # Jinja2 templates
│ └── utils/ # Validators, path builders
└── generated_project/ # Default output directory
Customizing Templates
Templates are real Jinja2 .j2 files in hexagon_generator/templates/crud/. Edit them to customize generated code.
They use <<...>> for variables and <%...%> for blocks (instead of Jinja's
default {{ }} / {% %}) because the generated output is Python/FastAPI
code that itself uses {} and [] constantly (dicts, f-strings, route
paths, list[...]); the usual delimiters would collide with that and force
escaping.
Documentation
- Hexagon Generator README - Generator details
Contributing
Contributions welcome! Areas to improve:
- Additional generators (GraphQL, gRPC, etc.)
- Template customization options
- Test generation
- Documentation generation
License
MIT — see LICENSE.
Acknowledgments
Built with:
- FastAPI
- SQLAlchemy 2.0
- Pydantic V2
- Jinja2
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fastapi_hexagon-0.3.1.tar.gz.
File metadata
- Download URL: fastapi_hexagon-0.3.1.tar.gz
- Upload date:
- Size: 114.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
74c3c8f109d730d0fd147e3e5f403306ffab870d297f7971a17fdf8720ef597b
|
|
| MD5 |
8f0abffda923a1a6db380c299dace059
|
|
| BLAKE2b-256 |
593206f3be5591001be254de078fb86ef388ade2e13d1d5a848c3c3565fde341
|
File details
Details for the file fastapi_hexagon-0.3.1-py3-none-any.whl.
File metadata
- Download URL: fastapi_hexagon-0.3.1-py3-none-any.whl
- Upload date:
- Size: 156.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
da945bd87f578c211825e09db0f3b025c8217431f98da99d92a5e4abfb93c589
|
|
| MD5 |
d5f1946beef3264b2c15a5d901ff8f22
|
|
| BLAKE2b-256 |
bc5ce5f5501975ca6059c51487daad846c476922757207ec53a0e5b4df8ff896
|