Skip to content

Architecture overview โ€‹

Layer structure โ€‹

nene2-python follows Clean Architecture. Dependencies flow from the outside in.

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  HTTP Handler (FastAPI router)              โ”‚
โ”‚  parse request โ†’ call use-case โ†’ response  โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚  UseCase                                    โ”‚
โ”‚  Business logic โ€” no HTTP or DB knowledge  โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚  RepositoryInterface (ABC)                  โ”‚
โ”‚  Contract for the operations the domain     โ”‚
โ”‚  needs                                      โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚  ConcreteRepository                         โ”‚
โ”‚  SQLAlchemy / InMemory implementations      โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Layer responsibilities โ€‹

HTTP Handler โ€‹

  • Single responsibility: parse the request, call a UseCase, return a response
  • Uses Pydantic BaseModel for request body validation (HTTP boundary only)
  • Contains zero domain logic
  • Exposed via a make_xxx_router() factory function
python
@router.post("", status_code=201)
async def create_note(body: CreateNoteBody) -> JSONResponse:
    note = create_use_case.execute(CreateNoteInput(title=body.title, body=body.body))
    return JSONResponse({"id": note.id, "title": note.title, "body": note.body}, status_code=201)

UseCase โ€‹

  • Single responsibility: implement one business rule
  • One method: execute(input_: XxxInput) -> XxxOutput
  • No import fastapi, no import sqlalchemy
  • Does not call other UseCases
  • Testable with InMemoryRepository alone

RepositoryInterface โ€‹

  • Defined as an ABC โ€” the UseCase depends only on the interface
  • Same interface is implemented by InMemory and SQLAlchemy versions
  • find_all, find_by_id, save, update, delete, count

ConcreteRepository โ€‹

  • SQLAlchemy Core (no ORM) with parameterised queries
  • Queries are executed via SqlAlchemyQueryExecutor
  • Table schema: the example app uses a central src/example/schema.py; for new projects, define ensure_schema() in each domain's sqlalchemy_repository.py and call each from create_app()

Middleware stack โ€‹

Requests pass through each middleware from outermost to innermost:

BearerTokenMiddleware        Authentication (Bearer Token)
ApiKeyAuthMiddleware         Authentication (API Key)
CORSMiddleware               CORS
ThrottleMiddleware           Rate limiting (fixed window)
RequestSizeLimitMiddleware   Payload size enforcement
RequestLoggingMiddleware     Structured request logging (structlog)
RequestIdMiddleware          X-Request-ID generation / propagation
SecurityHeadersMiddleware    Security response headers
ErrorHandlerMiddleware       Exceptions โ†’ RFC 9457 Problem Details

Dependency injection โ€‹

FastAPI's Depends is used at the HTTP boundary only. UseCases and repositories are wired via constructor injection in app.py.

python
# app.py โ€” wiring
note_repo = SqlAlchemyNoteRepository(executor)
app.include_router(make_note_router(
    list_use_case=ListNotesUseCase(note_repo),
    create_use_case=CreateNoteUseCase(note_repo),
    ...
))

Domain package layout โ€‹

src/example/<domain>/
  __init__.py
  entity.py              โ€” @dataclass(frozen=True, slots=True)
  repository.py          โ€” ABC + InMemory implementation
  exceptions.py          โ€” XxxNotFoundException + ExceptionHandler
  use_case.py            โ€” 5 UseCases + Input/Output DTOs
  handler.py             โ€” FastAPI router factory
  sqlalchemy_repository.py โ€” SQL backend

Released under the MIT License.