Presentation
A thin edge that maps the wire model to a command, calls one use case, and maps failures back out.
Presentation is the incoming adapter. It turns an outside request into one use case call, then turns the result or the failure into the response that caller understands. A screen, an endpoint, and a job runner are all presentation when they are the thing that invokes the workflow.
What lives here
| Artifact | Notes example | Why it is here |
|---|---|---|
| Entry point | NotesEndpoint.save or a submit handler |
Receives the outside call |
| Wire model | SaveNotePayload |
Fields and names the client speaks |
| Mapper | toSaveNoteCommand |
Wire model to command, result to wire model |
| Failure mapper | InvalidTitle to the client's error |
The caller does not import domain types |
The entry point stays thin:
save(request):
command = toSaveNoteCommand(request.payload)
result = saveNote.execute(command)
return toSaveNoteResponse(result)Auth context that arrived with the request (who is calling) is read here and placed on the command. The policy that decides whether that person may save a note is a use case step, or a domain rule, depending on whether it is a workflow or an invariant. The entry point does not re-implement it.
The wire model
The payload is the third model at the boundary. It exists to be serialized. It is allowed to be awkward in ways the entity is not: optional fields, names that match a public API, ids omitted on create because the server assigns them.
SaveNotePayload
title
body
SaveNoteResponse
id
title
body
createdAtThe client sends no id and no createdAt. The response has both, because the use case created them. That difference is a reason the payload is not a Note. If the public API renames body to text, the mapper changes. Note does not.
Errors across a boundary
Failures mean different things, and presentation is where they become a response.
| Failure | Raised by | What presentation does |
|---|---|---|
InvalidTitle |
Domain, while creating the note | A client error that names the field |
| Not found | Application, when a load returns nothing the workflow required | A client error for an unknown id |
| Store timeout, connection reset | Infrastructure | A server failure. The title was fine |
Do not catch a store timeout inside the domain and rethrow it as InvalidTitle. Do not let the use case format an error string for a particular client. Map at the edge, once, so a second entry point can map the same failure differently.
Unexpected failures can stay unexpected. Presentation maps the ones it knows. A programming bug is not a domain failure and does not need a polite field error.
What stays outside
- Constructing
SqlNoteRepositoryor any concrete adapter - Business invariants (
titleis not blank) - Multi-step workflows
- Query text
If the entry point grows past the map-call-map shape, the extra steps belong in the use case. The edge is replaceable: the same SaveNote serves an HTTP route, a generated RPC endpoint, or a test that calls execute directly.