In Haskell WAI, how do I add headers as middleware?
I am trying to understand Middleware by writing a very simple session manager.
I need to add a header SetCookie
in the response. I went through the package wai-extra
and found wai-session
.
I'm using wai-3.0.2, which doesn't seem to give me direct access to constructors like Response, and all the examples I've found follow the pattern Response(..)
for adding headers.
Can you point me in the right direction?
source to share
Edit: Version 3.0.3.0 of Wai introduces a helper function mapResponseHeaders
which is the same as mapHeader
in the example below. This means that the example Response
no longer needs to match patterns.
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)
Something is working for me, and I think I understand it, but I would really like the feedback and suggestions. I am new to Haskell and this is my first use of Wai. My biggest stumbling block was not realizing that the app type changed in Wai 3.0.0 to the continuation style. (The documentation says it very clearly , I just skipped 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 didn't try to change the headers for ResponseRaw
because I couldn't figure out how to do it.
I'm not sure if it's clear enough what addHeader
partially applies and is the continuation function passed into the internal 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 a case for ResponseRaw.
source to share