Get the FREE Ultimate OpenClaw Setup Guide →

python-fastapi-ddd-presentation-skill

npx machina-cli add skill iktakahiro/python-fastapi-ddd-skill/python-fastapi-ddd-presentation-skill --openclaw
Files (1)
SKILL.md
3.0 KB

FastAPI Presentation Layer (DDD / Onion Architecture)

This skill focuses on the Presentation layer only: FastAPI routes/handlers, Pydantic schemas, and HTTP error mapping. It assumes you already have Domain + UseCase layers and repository wiring.

Non-negotiables (Onion rule)

  • Presentation is the outermost layer: it can depend on UseCase and Domain types, but Domain must not depend on FastAPI/Pydantic.
  • Keep business rules inside Domain/UseCase. Presentation does:
    • request parsing/validation (shape, basic constraints)
    • conversion primitives → Value Objects
    • calling usecase.execute(...)
    • mapping Domain exceptions → HTTPException
    • conversion Entity → response schema

Recommended structure (per aggregate)

presentation/
  api/
    {aggregate}/
      handlers/
      schemas/
      error_messages/

Implementation checklist (per endpoint)

  1. Depend on UseCase interface via Depends(get_*_usecase).
  2. Convert inputs (UUID, str, etc.) into Domain Value Objects.
  3. Handle ValueError (from Value Objects) as 400 Bad Request.
  4. Execute the use case.
  5. Map Domain exceptions (e.g., NotFound, lifecycle errors) to 404/400.
  6. Return response model using Schema.from_entity(entity) (or equivalent).
  7. Document errors in OpenAPI using responses={...: {'model': ...}}.

Route handler pattern (based on dddpy)

Prefer a small “route registrar” class per aggregate.

class TodoApiRouteHandler:
    def register_routes(self, app: FastAPI):
        @app.post("/todos", response_model=TodoSchema, status_code=201)
        def create_todo(
            data: TodoCreateSchema,
            usecase: CreateTodoUseCase = Depends(get_create_todo_usecase),
        ):
            try:
                title = TodoTitle(data.title)
                description = (
                    TodoDescription(data.description) if data.description else None
                )
            except ValueError as e:
                raise HTTPException(status_code=400, detail=str(e)) from e

            todo = usecase.execute(title, description)
            return TodoSchema.from_entity(todo)

Pydantic schemas

  • Request schemas: validate shape + basic constraints (min/max length, optional fields).
  • Response schemas: provide from_entity() to convert Domain types (UUID/datetime) into JSON-friendly primitives (e.g., timestamps as milliseconds).

For detailed templates and a fuller walk-through, read references/PRESENTATION.md.

Source

git clone https://github.com/iktakahiro/python-fastapi-ddd-skill/blob/main/skills/python-fastapi-ddd-presentation-skill/SKILL.mdView on GitHub

Overview

This skill handles the Presentation layer of a Python DDD + Onion Architecture app using FastAPI routes, Pydantic schemas, and HTTP error mapping. It covers request parsing, Value Object conversion, UseCase invocation, and converting Domain results to response schemas, while keeping Domain free from FastAPI concerns. It follows the dddpy reference and encourages a per-aggregate route pattern.

How This Skill Works

Requests are validated by Pydantic schemas, then primitive inputs are converted into Domain Value Objects. The route handler invokes the UseCase via Depends, maps Domain exceptions to HTTP errors, and returns a response schema built from the resulting Entity. It also documents errors for OpenAPI using the route decorators.

When to Use It

  • When adding or refactoring endpoints that invoke UseCases and convert primitives to Domain Value Objects or Entities
  • To ensure Domain rules stay in Domain/UseCase and Presentation handles validation and mapping
  • To map Domain exceptions to HTTP status codes such as 404 Not Found or 400 Bad Request
  • To document error responses in OpenAPI for client developers
  • To organize code with a per-aggregate route registrar pattern

Quick Start

  1. Step 1: Wire a per aggregate route registrar and inject the UseCase with Depends
  2. Step 2: Validate inputs and convert primitives to Domain Value Objects inside the handler
  3. Step 3: Execute the UseCase, map Domain exceptions to HTTP errors, and return Schema.from_entity(entity)

Best Practices

  • Keep Domain independent from FastAPI and Pydantic in the Presentation layer
  • Inject UseCases via Depends(get_*_usecase) for clean wiring
  • Validate inputs and convert to Domain Value Objects, handling ValueError as 400
  • Map Domain exceptions to HTTP errors and preserve 404/400 semantics
  • Return responses with Schema.from_entity(entity) and document errors in OpenAPI

Example Use Cases

  • CreateTodo: POST /todos -> CreateTodoUseCase, TodoCreateSchema, TodoSchema
  • GetTodo: GET /todos/{id} -> GetTodoUseCase, 404 if not found
  • UpdateTodo: PATCH /todos/{id} -> UpdateTodoUseCase, TodoUpdateSchema, 400/404
  • DeleteTodo: DELETE /todos/{id} -> DeleteTodoUseCase, 204 or 404
  • ListTodos: GET /todos -> ListTodosUseCase, TodoListSchema

Frequently Asked Questions

Add this skill to your agents
Sponsor this space

Reach thousands of developers