I am trying to understand Middleware by writing a very simple session manager.
I need to add the SetCookie
header in the response. I've looked at the wai-extra
package, and found wai-session
.
I'm using wai-3.0.2, which doesn't seem to give me direct access to the type constructors for Response, and all of the examples I've found pattern match on Response(..)
to add headers.
Can you point me in the right direction?
Edit: Version 3.0.3.0 of Wai introduces a helper function mapResponseHeaders
that is the same as mapHeader
in the example below. This means the example no longer needs to pattern match on Response
.
import Network.HTTP.Types (ResponseHeaders, Header)
import Network.Wai (Middleware, Response, mapResponseHeaders)
withHeader :: Header -> Middleware
withHeader h app req respond = app req $ respond . addHeader h
addHeader :: Header -> Response -> Response
addHeader h = mapResponseHeaders (\hs -> h:hs)
I have something working, and think I understand it, but would really like feedback and suggestions. I'm new to Haskell, and this is my first use of Wai. My biggest stumbling block was not realizing that the Application type changed in Wai 3.0.0 to a continuation passing style. (The documentation states this very clearly; I just missed it the first 15 times I read it.)
import Network.HTTP.Types (ResponseHeaders, Header)
import Network.Wai (Middleware)
import Network.Wai.Internal (Response(..))
withHeader :: Header -> Middleware
withHeader h app req respond = app req $ respond . addHeader h
mapHeader :: (ResponseHeaders -> ResponseHeaders) -> Response -> Response
mapHeader f (ResponseFile s h b1 b2) = ResponseFile s (f h) b1 b2
mapHeader f (ResponseBuilder s h b) = ResponseBuilder s (f h) b
mapHeader f (ResponseStream s h b) = ResponseStream s (f h) b
mapHeader _ r@(ResponseRaw _ _) = r
addHeader :: Header -> Response -> Response
addHeader h = mapHeader (\hs -> h:hs)
I made no attempt to modify headers for a ResponseRaw
, because I couldn't figure out how.
I'm not sure it's clear enough that addHeader
is partially applied and is the continuation function passed to the inner Application. This form might be clearer (or uglier):
withHeader h app req respond = app req $ \resp -> respond $ addHeader h resp
I copied mapHeader
from wai-session, but added the case for ResponseRaw.