Request lifecycle
An adapter translates one protocol into calls on application contracts. It owns HTTP concerns; it does not own business rules or SQL.
flowchart LR C["Client"] --> A["Transport adapter"] A --> H["Authenticate and parse"] H --> O["operation::check"] O --> S["Contract service"] S --> I["Implementation"] I --> P["Provider: database, cache, service"] S --> R["Return value or AppError"] R --> A A --> C
1. The adapter receives the request
The adapter:
- extracts path, query, headers, cookies, and body;
- authenticates credentials at the edge;
- builds a trusted
CallContextonly after authentication succeeds; - validates and maps transport errors.
It calls the contract. It never imports the concrete database or policy crate.
2. The operation checks access and validates input
.await?;
Access is enforced before validation. A denied caller cannot reach
Validate::validate. See Contracts and traits and
Calls and transactions.
3. The contract service performs the work
The service depends on ports, not providers. It may:
- call repository methods on a shared
Session; - open a
TransactionScopewhen several statements must succeed together; - use a cache or another capability through its contract;
- return a domain value or a structured
AppError.
4. The implementation carries out storage or policy
An implementation such as iet-db-timescale
provides the Session, repository, and transaction machinery. Policy crates such
as iet-auth-rbac implement authorization ports.
The implementation knows its provider. It does not know which adapter called it.
5. The adapter maps the result
The adapter maps domain values and AppError kinds to its protocol:
ErrorKind | HTTP mapping |
|---|---|
Validation | 422 Unprocessable Entity |
Unauthenticated | 401 Unauthorized |
Forbidden | 403 Forbidden |
NotFound | 404 Not Found |
Conflict | 409 Conflict |
Unavailable | 503 Service Unavailable |
DeadlineExceeded | 504 Gateway Timeout |
Internal | 500 Internal Server Error |
The transport adapter owns the mapping. Core does not encode HTTP.
What stays out of the adapter
- Business rules and invariants.
- SQL and migrations.
- Policy decisions about roles or resource grants.
- Session or transaction lifetime beyond what the contract requires.
What stays out of the contract
- HTTP status codes, headers, cookies, and HTML.
- A concrete database, cache, or message broker.
- Framework-specific runtime types.
That separation is what makes the same capability callable from an HTMX page, a JSON API, a command-line tool, or a background worker.