| Safe Haskell | None |
|---|---|
| Language | GHC2021 |
Ecluse.Core.Server.Contract
Description
The response-contract algebra: one value interpreted as both wire behaviour and capability-manifest documentation.
A ResponseContract is indexed by the value a handler must produce. Its constructor is
private: callers can only build one from the leaf contracts in this module and combine
those leaves with chooseContract. Each leaf owns both its ResponseDoc and the function
that renders its payload, so those two interpretations cannot be supplied separately.
The route layer existentially packages a contract with a handler producing that
contract's response type. The runtime gives the handler only the corresponding typed
responder; a handler therefore cannot reach WAI with a status or body outside its route's
contract. bodilessContract is the same interpretation for HEAD: statuses and headers
are preserved while every documented and emitted body is removed.
Owned JSON bodies use the same autodocodec JSONCodec for encoding here and schema
generation in the manifest tier. An intentionally transparent upstream relay is different:
its status, media type, and bytes are not Écluse's to constrain, so
passthroughContract documents an explicit OpenAPI default response instead of claiming
a false closed set.
Synopsis
- data BodySchema
- data RequestSpec = RequestSpec {}
- data ResponseStatus
- data ResponseDoc = ResponseDoc {}
- data ResponseContract response
- responseDocs :: ResponseContract response -> [ResponseDoc]
- responseToWai :: ResponseContract response -> response -> Response
- bodilessContract :: ResponseContract response -> ResponseContract response
- data ResponseValue a
- responseValue :: [Header] -> a -> ResponseValue a
- jsonContract :: Status -> Text -> JSONCodec a -> ResponseContract (ResponseValue a)
- documentedJsonContract :: Status -> Text -> Text -> ResponseContract (ResponseValue LByteString)
- emptyContract :: Status -> Text -> ResponseContract (ResponseValue ())
- data VariableResponse a
- variableResponse :: Status -> [Header] -> a -> VariableResponse a
- variableOpaqueContract :: ByteString -> Text -> ResponseContract (VariableResponse LByteString)
- data PassthroughBody
- data PassthroughResponse
- passthroughResponse :: Status -> [Header] -> PassthroughBody -> PassthroughResponse
- passthroughContract :: Text -> ResponseContract PassthroughResponse
- data ResponseChoice a b
- = FirstResponse a
- | SecondResponse b
- chooseContract :: ResponseContract a -> ResponseContract b -> ResponseContract (ResponseChoice a b)
- encodeBody :: JSONCodec a -> a -> LByteString
Documented body shapes
data BodySchema Source #
The structural shape of a response body, kept OpenAPI-free in the core.
SchemaPassthrough is deliberately broad: it means the operation transparently relays
an upstream response whose media type and body shape are outside Écluse's control.
Constructors
| SchemaEmpty | No body at all. |
| SchemaOpaque ByteString | Opaque bytes under one known media type. |
| SchemaJson (JSONCodec a) | JSON encoded from the same codec the manifest renders as a schema. |
| SchemaDocumented Text | An imperatively assembled JSON document with a named manifest schema. |
| SchemaPassthrough | An upstream-controlled body under an upstream-controlled media type. |
data RequestSpec Source #
A request body a route accepts: its prose, requiredness, and documented shape.
Request decoding is not part of the response algebra. A hand-authored request schema still owes the separate conformance check described in the API-surface architecture.
Constructors
| RequestSpec | |
Fields
| |
data ResponseStatus Source #
Whether a documented response has one exact status or covers every other status.
Constructors
| ExactResponse Status | |
| DefaultResponse |
Instances
| Show ResponseStatus Source # | |
Defined in Ecluse.Core.Server.Contract Methods showsPrec :: Int -> ResponseStatus -> ShowS # show :: ResponseStatus -> String # showList :: [ResponseStatus] -> ShowS # | |
| Eq ResponseStatus Source # | |
Defined in Ecluse.Core.Server.Contract Methods (==) :: ResponseStatus -> ResponseStatus -> Bool # (/=) :: ResponseStatus -> ResponseStatus -> Bool # | |
data ResponseDoc Source #
One response entry for the capability manifest. This is a projection of a
ResponseContract leaf, never independently supplied by a route.
Constructors
| ResponseDoc | |
Fields
| |
A response contract
data ResponseContract response Source #
A response contract indexed by the only value its handler may answer with.
The constructor is private. The list and renderer can therefore only be extended together
through this module's leaves and chooseContract.
responseDocs :: ResponseContract response -> [ResponseDoc] Source #
The manifest projection of a response contract.
responseToWai :: ResponseContract response -> response -> Response Source #
Render one value through its contract and into WAI. This is the only application
boundary at which a route response becomes an unrestricted WAI Response.
bodilessContract :: ResponseContract response -> ResponseContract response Source #
Derive the HEAD interpretation of a contract: the same response alternatives,
statuses, and headers, with no documented or emitted body.
Exact response leaves
data ResponseValue a Source #
A payload for an exact-status response, carrying additional response headers.
responseValue :: [Header] -> a -> ResponseValue a Source #
Supply the additional headers and payload for an exact response leaf.
jsonContract :: Status -> Text -> JSONCodec a -> ResponseContract (ResponseValue a) Source #
One exact JSON response, encoded through the codec its manifest schema uses.
documentedJsonContract :: Status -> Text -> Text -> ResponseContract (ResponseValue LByteString) Source #
One exact JSON response whose bytes are assembled imperatively and whose schema is the named hand-authored component in the manifest.
emptyContract :: Status -> Text -> ResponseContract (ResponseValue ()) Source #
One exact bodiless response.
Open response leaves
data VariableResponse a Source #
A response whose status is supplied by the handler while its media type remains fixed by the contract. Used for the publication target's arbitrary JSON-labelled status.
variableResponse :: Status -> [Header] -> a -> VariableResponse a Source #
Supply a dynamic status, additional headers, and body to a variable-status leaf.
variableOpaqueContract :: ByteString -> Text -> ResponseContract (VariableResponse LByteString) Source #
An OpenAPI default response carrying opaque bytes under a fixed media type.
The schema is intentionally binary even for application/json: Écluse relays the
publication target's bytes without parsing them, so it must not promise they satisfy a
JSON schema it never checks.
data PassthroughBody Source #
The body of a transparent upstream response.
data PassthroughResponse Source #
A transparent upstream response: status, headers, and body all remain upstream's.
passthroughResponse :: Status -> [Header] -> PassthroughBody -> PassthroughResponse Source #
Build a transparent response value for passthroughContract.
passthroughContract :: Text -> ResponseContract PassthroughResponse Source #
An explicit OpenAPI default contract for a transparent upstream relay.
This is the honest contract when the proxy intentionally forwards arbitrary upstream statuses and media types. It prevents drift by documenting that open behaviour rather than placing an inaccurate finite status set beside it.
Combining closed alternatives
data ResponseChoice a b Source #
A binary response choice. Nesting ResponseChoices forms a closed route response
sum without type-level programming; chooseContract builds its two matching
interpretations together.
Constructors
| FirstResponse a | |
| SecondResponse b |
chooseContract :: ResponseContract a -> ResponseContract b -> ResponseContract (ResponseChoice a b) Source #
Combine two response contracts into a closed choice of their alternatives.
Rendering JSON through a codec
encodeBody :: JSONCodec a -> a -> LByteString Source #
Encode a JSON value to bytes through its autodocodec codec.