@@ -23,7 +23,8 @@
2323-- The value is added to the header specified by the type (@Location@ in the
2424-- example above).
2525module Servant.API.ResponseHeaders
26− ( Headers(..)
26+ ( -- * "Static" response headers, tracked at the type-level
27+ Headers(..)
2728 , ResponseHeader (..)
2829 , AddHeader
2930 , addHeader
@@ -32,11 +33,18 @@ module Servant.API.ResponseHeaders
3233 , GetHeaders(getHeaders)
3334 , HeaderValMap
3435 , HList(..)
36+
37+ , -- * "Dynamic" response headers
38+ DynHeaders(..)
39+ , DynResponse(..)
40+ , withDynHeaders
3541 ) where
3642
3743import Data.ByteString.Char8 as BS
3844 (ByteString, init, pack, unlines)
3945import qualified Data.CaseInsensitive as CI
46+import Data.Map
47+ (Map)
4048import Data.Proxy
4149import Data.Typeable
4250 (Typeable)
@@ -51,8 +59,9 @@ import Prelude.Compat
5159import Servant.API.Header
5260 (Header)
5361
54−-- | Response Header objects. You should never need to construct one directly.
55−-- Instead, use 'addOptionalHeader'.
62+-- | Response Header objects where each header name is tracked at the type-level.
63+-- You should never need to construct one directly. Instead, use
64+-- 'addOptionalHeader'.
5665data Headers ls a = Headers { getResponse :: a
5766 -- ^ The underlying value of a 'Headers'
5867 , getHeadersHList :: HList ls
@@ -166,6 +175,25 @@ addHeader = addOptionalHeader . Header
166175noHeader :: AddHeader h v orig new => orig -> new
167176noHeader = addOptionalHeader MissingHeader
168177
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.
182+--
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.
185+data DynHeaders a
186+
187+data DynResponse a = DynResponse
188+ { dynResponse :: a
189+ , dynHeaders :: Map HTTP.HeaderName ByteString
190+ } deriving (Typeable, Eq, Show, Functor)
191+
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
196+
169197-- $setup
170198-- >>> import Servant.API
171199-- >>> import Data.Aeson