Response State Transitions¶
The response
field in the Conn is a value provided by the server backend.
Middleware often constrain the response
field to be a value implementing the
Response
type class. This makes it possible to use response writing
operations without depending on a specific server backend.
The state of a response is tracked in its last type parameter. This state
tracking, and the type-indexed middleware using the response, guarantee
correctness in response handling, preventing incorrect ordering of headers and
body writes, incomplete responses, or other such mistakes. Let us have a look
at the type signatures of some of response writing functions in
Hyper.Response
.
We see that headers
takes a foldable collection of headers, and
gives back a middleware that, given a connection where headers are ready
to be written (HeadersOpen
), writes all specified headers, writes
the separating CRLF before the HTTP body, and marks the state of the
response as being ready to write the body (BodyOpen
).
headers
:: forall t m req res b c
. ( Foldable f
, Monad m
, Response res m b
)
=> f Header
-> Middleware
m
(Conn req (res HeadersOpen) c)
(Conn req (res BodyOpen) c)
Unit
To be used in combination with headers
, the respond
function
takes some ResponseWritable m r b
, and gives back a middleware that, given
a connection where all headers have been written, writes a response, and
marks the state of the response as ended.
respond
:: forall m r b req res c
. ( Monad m
, ResponseWritable b m r
, Response res m b
)
=> r
-> Middleware
m
(Conn req (res BodyOpen) c)
(Conn req (res ResponseEnded) c)
Unit
The ResponseWritable
type class describes types that can be written as
responses. It takes three type parameters, where b
is the target type,
m
is a base monad for the Middleware returned, and r
is the original
response type,
class ResponseWritable b m r where
toResponse :: forall i. r -> Middleware m i i b
This mechanism allows servers to provide specific types for the response
body, along with instances for common response types. When using the
Node server, which has a response body type wrapping Buffer
, you can
still respond with a String
or HTML
value directly.
Aside from convenience in having a single function for most response
types and servers, the polymorphism of respond
lets middleware be
decoupled from specific servers. It only requires an instance matching
the response type used by the middleware and the type required by the
server.