@@ -23,7 +23,8 @@
23-- The value is added to the header specified by the type (@Location@ in the
23-- The value is added to the header specified by the type (@Location@ in the
24-- example above).
24-- example above).
25module Servant.API.ResponseHeaders
25module Servant.API.ResponseHeaders
26+ ( -- * "Static" response headers, tracked at the type-level
26− ( Headers(..)
27+ Headers(..)
27 , ResponseHeader (..)
28 , ResponseHeader (..)
28 , AddHeader
29 , AddHeader
29 , addHeader
30 , addHeader
@@ -32,11 +33,18 @@ module Servant.API.ResponseHeaders
32 , GetHeaders(getHeaders)
33 , GetHeaders(getHeaders)
33 , HeaderValMap
34 , HeaderValMap
34 , HList(..)
35 , HList(..)
37+ , -- * "Dynamic" response headers
37import Data.ByteString.Char8 as BS
43import Data.ByteString.Char8 as BS
38 (ByteString, init, pack, unlines)
44 (ByteString, init, pack, unlines)
39import qualified Data.CaseInsensitive as CI
45import qualified Data.CaseInsensitive as CI
40import Data.Proxy
48import Data.Proxy
41import Data.Typeable
49import Data.Typeable
42 (Typeable)
50 (Typeable)
@@ -51,8 +59,9 @@ import Prelude.Compat
51import Servant.API.Header
59import Servant.API.Header
62+-- | Response Header objects where each header name is tracked at the type-level.
54−-- | Response Header objects. You should never need to construct one directly.
63+-- You should never need to construct one directly. Instead, use
55−-- Instead, use 'addOptionalHeader'.
64+-- 'addOptionalHeader'.
56data Headers ls a = Headers { getResponse :: a
65data Headers ls a = Headers { getResponse :: a
57 -- ^ The underlying value of a 'Headers'
66 -- ^ The underlying value of a 'Headers'
58 , getHeadersHList :: HList ls
67 , getHeadersHList :: HList ls
@@ -166,6 +175,25 @@ addHeader = addOptionalHeader . Header
166noHeader :: AddHeader h v orig new => orig -> new
175noHeader :: AddHeader h v orig new => orig -> new
167noHeader = addOptionalHeader MissingHeader
176noHeader = addOptionalHeader MissingHeader
178+-- | Combinator to use when you want your endpoint to return a response
179+-- along with some response headers, dynamically,
180+-- by simply building a value of type 'DynResponse a', which is just a
181+-- response of type @a@ along with a map from header names to header values.
183+-- For all other interpretations than the server one, this combinator basically
184+-- has no effect and behaves just as if you were using @a@ directly.
187+data DynResponse a = DynResponse
189+ , dynHeaders :: Map HTTP.HeaderName ByteString
190+ } deriving (Typeable, Eq, Show, Functor)
192+-- | Build a \"response with headers\", where the headers are
193+-- provided at runtime as a 'Map' from header name to header value.
194+withDynHeaders :: a -> Map HTTP.HeaderName ByteString -> DynResponse a
195+withDynHeaders = DynResponse
170-- >>> import Servant.API
198-- >>> import Servant.API
171-- >>> import Data.Aeson
199-- >>> import Data.Aeson