Skip to main content

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

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

fastapi_hexagon-0.3.1.tar.gz (114.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fastapi_hexagon-0.3.1-py3-none-any.whl (156.7 kB view details)

Uploaded Python 3

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

Hashes for fastapi_hexagon-0.3.1.tar.gz
Algorithm Hash digest
SHA256 74c3c8f109d730d0fd147e3e5f403306ffab870d297f7971a17fdf8720ef597b
MD5 8f0abffda923a1a6db380c299dace059
BLAKE2b-256 593206f3be5591001be254de078fb86ef388ade2e13d1d5a848c3c3565fde341

See more details on using hashes here.

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

Hashes for fastapi_hexagon-0.3.1-py3-none-any.whl
Algorithm Hash digest
SHA256 da945bd87f578c211825e09db0f3b025c8217431f98da99d92a5e4abfb93c589
MD5 d5f1946beef3264b2c15a5d901ff8f22
BLAKE2b-256 bc5ce5f5501975ca6059c51487daad846c476922757207ec53a0e5b4df8ff896

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.3.1 This release

2 files

0.2.0

2 files

0.1.1

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page