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
Metadata
Release files for fastapi-hexagon 0.3.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| fastapi_hexagon-0.3.1.tar.gz | 114.9 kB | Without provenance | Details for fastapi_hexagon-0.3.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| fastapi_hexagon-0.3.1-py3-none-any.whl | Python 3 | none | any | Details for fastapi_hexagon-0.3.1-py3-none-any.whl |
Total release size: 271.6 kB
Release files / fastapi_hexagon-0.3.1.tar.gz
| Download URL | fastapi_hexagon-0.3.1.tar.gz |
|---|---|
| Size | 114.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
74c3c8f109d730d0fd147e3e5f403306ffab870d297f7971a17fdf8720ef597b
|
|
BLAKE2b-256 checksum How to use checksums |
593206f3be5591001be254de078fb86ef388ade2e13d1d5a848c3c3565fde341
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is 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}
|
Release files / fastapi_hexagon-0.3.1-py3-none-any.whl
| Download URL | fastapi_hexagon-0.3.1-py3-none-any.whl |
|---|---|
| Size | 156.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
da945bd87f578c211825e09db0f3b025c8217431f98da99d92a5e4abfb93c589
|
|
BLAKE2b-256 checksum How to use checksums |
bc5ce5f5501975ca6059c51487daad846c476922757207ec53a0e5b4df8ff896
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is 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}
|
Security for fastapi-hexagon 0.3.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.