{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_HADDOCK not-home #-}
module Servant.API.ResponseHeaders
( Headers(..)
, ResponseHeader (..)
, AddHeader
, addHeader
, noHeader
, HasResponseHeader
, lookupResponseHeader
, BuildHeadersTo(buildHeadersTo)
, GetHeaders(getHeaders)
, GetHeaders'
, HeaderValMap
, HList(..)
) where
import Control.DeepSeq
(NFData (..))
import Data.ByteString.Char8 as BS
(ByteString, init, pack, unlines)
import qualified Data.CaseInsensitive as CI
import Data.Proxy
import Data.Typeable
(Typeable)
import GHC.TypeLits
(KnownSymbol, Symbol, symbolVal)
import qualified Network.HTTP.Types.Header as HTTP
import Web.HttpApiData
(FromHttpApiData, ToHttpApiData, parseHeader, toHeader)
import Prelude ()
import Prelude.Compat
import Servant.API.ContentTypes
(JSON, PlainText, FormUrlEncoded, OctetStream,
MimeRender(..))
import Servant.API.Header
(Header)
data ls a = { Headers ls a -> a
getResponse :: a
, :: HList ls
} deriving (a -> Headers ls b -> Headers ls a
(a -> b) -> Headers ls a -> Headers ls b
(forall a b. (a -> b) -> Headers ls a -> Headers ls b)
-> (forall a b. a -> Headers ls b -> Headers ls a)
-> Functor (Headers ls)
forall (ls :: [*]) a b. a -> Headers ls b -> Headers ls a
forall (ls :: [*]) a b. (a -> b) -> Headers ls a -> Headers ls b
forall a b. a -> Headers ls b -> Headers ls a
forall a b. (a -> b) -> Headers ls a -> Headers ls b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: a -> Headers ls b -> Headers ls a
$c<$ :: forall (ls :: [*]) a b. a -> Headers ls b -> Headers ls a
fmap :: (a -> b) -> Headers ls a -> Headers ls b
$cfmap :: forall (ls :: [*]) a b. (a -> b) -> Headers ls a -> Headers ls b
Functor)
instance (NFDataHList ls, NFData a) => NFData (Headers ls a) where
rnf :: Headers ls a -> ()
rnf (Headers a
x HList ls
hdrs) = a -> ()
forall a. NFData a => a -> ()
rnf a
x () -> () -> ()
`seq` HList ls -> ()
forall a. NFData a => a -> ()
rnf HList ls
hdrs
data (sym :: Symbol) a
= a
|
| ByteString
deriving (Typeable, ResponseHeader sym a -> ResponseHeader sym a -> Bool
(ResponseHeader sym a -> ResponseHeader sym a -> Bool)
-> (ResponseHeader sym a -> ResponseHeader sym a -> Bool)
-> Eq (ResponseHeader sym a)
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
forall (sym :: Symbol) a.
Eq a =>
ResponseHeader sym a -> ResponseHeader sym a -> Bool
/= :: ResponseHeader sym a -> ResponseHeader sym a -> Bool
$c/= :: forall (sym :: Symbol) a.
Eq a =>
ResponseHeader sym a -> ResponseHeader sym a -> Bool
== :: ResponseHeader sym a -> ResponseHeader sym a -> Bool
$c== :: forall (sym :: Symbol) a.
Eq a =>
ResponseHeader sym a -> ResponseHeader sym a -> Bool
Eq, Int -> ResponseHeader sym a -> ShowS
[ResponseHeader sym a] -> ShowS
ResponseHeader sym a -> String
(Int -> ResponseHeader sym a -> ShowS)
-> (ResponseHeader sym a -> String)
-> ([ResponseHeader sym a] -> ShowS)
-> Show (ResponseHeader sym a)
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
forall (sym :: Symbol) a.
Show a =>
Int -> ResponseHeader sym a -> ShowS
forall (sym :: Symbol) a. Show a => [ResponseHeader sym a] -> ShowS
forall (sym :: Symbol) a. Show a => ResponseHeader sym a -> String
showList :: [ResponseHeader sym a] -> ShowS
$cshowList :: forall (sym :: Symbol) a. Show a => [ResponseHeader sym a] -> ShowS
show :: ResponseHeader sym a -> String
$cshow :: forall (sym :: Symbol) a. Show a => ResponseHeader sym a -> String
showsPrec :: Int -> ResponseHeader sym a -> ShowS
$cshowsPrec :: forall (sym :: Symbol) a.
Show a =>
Int -> ResponseHeader sym a -> ShowS
Show, a -> ResponseHeader sym b -> ResponseHeader sym a
(a -> b) -> ResponseHeader sym a -> ResponseHeader sym b
(forall a b.
(a -> b) -> ResponseHeader sym a -> ResponseHeader sym b)
-> (forall a b. a -> ResponseHeader sym b -> ResponseHeader sym a)
-> Functor (ResponseHeader sym)
forall a b. a -> ResponseHeader sym b -> ResponseHeader sym a
forall a b.
(a -> b) -> ResponseHeader sym a -> ResponseHeader sym b
forall (sym :: Symbol) a b.
a -> ResponseHeader sym b -> ResponseHeader sym a
forall (sym :: Symbol) a b.
(a -> b) -> ResponseHeader sym a -> ResponseHeader sym b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: a -> ResponseHeader sym b -> ResponseHeader sym a
$c<$ :: forall (sym :: Symbol) a b.
a -> ResponseHeader sym b -> ResponseHeader sym a
fmap :: (a -> b) -> ResponseHeader sym a -> ResponseHeader sym b
$cfmap :: forall (sym :: Symbol) a b.
(a -> b) -> ResponseHeader sym a -> ResponseHeader sym b
Functor)
instance NFData a => NFData (ResponseHeader sym a) where
rnf :: ResponseHeader sym a -> ()
rnf ResponseHeader sym a
MissingHeader = ()
rnf (UndecodableHeader ByteString
bs) = ByteString -> ()
forall a. NFData a => a -> ()
rnf ByteString
bs
rnf (Header a
x) = a -> ()
forall a. NFData a => a -> ()
rnf a
x
data HList a where
HNil :: HList '[]
HCons :: ResponseHeader h x -> HList xs -> HList (Header h x ': xs)
class NFDataHList xs where rnfHList :: HList xs -> ()
instance NFDataHList '[] where rnfHList :: HList '[] -> ()
rnfHList HList '[]
HNil = ()
instance (y ~ Header h x, NFData x, NFDataHList xs) => NFDataHList (y ': xs) where
rnfHList :: HList (y : xs) -> ()
rnfHList (HCons ResponseHeader h x
h HList xs
xs) = ResponseHeader h x -> ()
forall a. NFData a => a -> ()
rnf ResponseHeader h x
h () -> () -> ()
`seq` HList xs -> ()
forall (xs :: [*]). NFDataHList xs => HList xs -> ()
rnfHList HList xs
xs
instance NFDataHList xs => NFData (HList xs) where
rnf :: HList xs -> ()
rnf = HList xs -> ()
forall (xs :: [*]). NFDataHList xs => HList xs -> ()
rnfHList
type family (f :: * -> *) (xs :: [*]) where
f '[] = '[]
f (Header h x ': xs) = Header h (f x) ': HeaderValMap f xs
class hs where
:: [HTTP.Header] -> HList hs
instance {-# OVERLAPPING #-} BuildHeadersTo '[] where
buildHeadersTo :: [Header] -> HList '[]
buildHeadersTo [Header]
_ = HList '[]
HNil
instance {-# OVERLAPPABLE #-} ( FromHttpApiData v, BuildHeadersTo xs, KnownSymbol h )
=> BuildHeadersTo (Header h v ': xs) where
buildHeadersTo :: [Header] -> HList (Header h v : xs)
buildHeadersTo [Header]
headers =
let wantedHeader :: CI ByteString
wantedHeader = ByteString -> CI ByteString
forall s. FoldCase s => s -> CI s
CI.mk (ByteString -> CI ByteString)
-> (String -> ByteString) -> String -> CI ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> ByteString
pack (String -> CI ByteString) -> String -> CI ByteString
forall a b. (a -> b) -> a -> b
$ Proxy h -> String
forall (n :: Symbol) (proxy :: Symbol -> *).
KnownSymbol n =>
proxy n -> String
symbolVal (Proxy h
forall k (t :: k). Proxy t
Proxy :: Proxy h)
matching :: [ByteString]
matching = Header -> ByteString
forall a b. (a, b) -> b
snd (Header -> ByteString) -> [Header] -> [ByteString]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Header -> Bool) -> [Header] -> [Header]
forall a. (a -> Bool) -> [a] -> [a]
filter (\(CI ByteString
h, ByteString
_) -> CI ByteString
h CI ByteString -> CI ByteString -> Bool
forall a. Eq a => a -> a -> Bool
== CI ByteString
wantedHeader) [Header]
headers
in case [ByteString]
matching of
[] -> ResponseHeader h v
forall (sym :: Symbol) a. ResponseHeader sym a
MissingHeader ResponseHeader h v -> HList xs -> HList (Header h v : xs)
forall (h :: Symbol) x (xs :: [*]).
ResponseHeader h x -> HList xs -> HList (Header h x : xs)
`HCons` [Header] -> HList xs
forall (hs :: [*]). BuildHeadersTo hs => [Header] -> HList hs
buildHeadersTo [Header]
headers
[ByteString]
xs -> case ByteString -> Either Text v
forall a. FromHttpApiData a => ByteString -> Either Text a
parseHeader (ByteString -> ByteString
BS.init (ByteString -> ByteString) -> ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ [ByteString] -> ByteString
BS.unlines [ByteString]
xs) of
Left Text
_err -> ByteString -> ResponseHeader h v
forall (sym :: Symbol) a. ByteString -> ResponseHeader sym a
UndecodableHeader (ByteString -> ByteString
BS.init (ByteString -> ByteString) -> ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ [ByteString] -> ByteString
BS.unlines [ByteString]
xs)
ResponseHeader h v -> HList xs -> HList (Header h v : xs)
forall (h :: Symbol) x (xs :: [*]).
ResponseHeader h x -> HList xs -> HList (Header h x : xs)
`HCons` [Header] -> HList xs
forall (hs :: [*]). BuildHeadersTo hs => [Header] -> HList hs
buildHeadersTo [Header]
headers
Right v
h -> v -> ResponseHeader h v
forall (sym :: Symbol) a. a -> ResponseHeader sym a
Header v
h ResponseHeader h v -> HList xs -> HList (Header h v : xs)
forall (h :: Symbol) x (xs :: [*]).
ResponseHeader h x -> HList xs -> HList (Header h x : xs)
`HCons` [Header] -> HList xs
forall (hs :: [*]). BuildHeadersTo hs => [Header] -> HList hs
buildHeadersTo [Header]
headers
class ls where
:: ls -> [HTTP.Header]
class hs where
:: HList hs -> [HTTP.Header]
instance GetHeadersFromHList hs => GetHeaders (HList hs) where
getHeaders :: HList hs -> [Header]
getHeaders = HList hs -> [Header]
forall (hs :: [*]). GetHeadersFromHList hs => HList hs -> [Header]
getHeadersFromHList
instance GetHeadersFromHList '[] where
getHeadersFromHList :: HList '[] -> [Header]
getHeadersFromHList HList '[]
_ = []
instance (KnownSymbol h, ToHttpApiData x, GetHeadersFromHList xs)
=> GetHeadersFromHList (Header h x ': xs)
where
getHeadersFromHList :: HList (Header h x : xs) -> [Header]
getHeadersFromHList HList (Header h x : xs)
hdrs = case HList (Header h x : xs)
hdrs of
Header x
val `HCons` HList xs
rest -> (CI ByteString
headerName , x -> ByteString
forall a. ToHttpApiData a => a -> ByteString
toHeader x
val) Header -> [Header] -> [Header]
forall a. a -> [a] -> [a]
: HList xs -> [Header]
forall (hs :: [*]). GetHeadersFromHList hs => HList hs -> [Header]
getHeadersFromHList HList xs
rest
UndecodableHeader ByteString
h `HCons` HList xs
rest -> (CI ByteString
headerName, ByteString
h) Header -> [Header] -> [Header]
forall a. a -> [a] -> [a]
: HList xs -> [Header]
forall (hs :: [*]). GetHeadersFromHList hs => HList hs -> [Header]
getHeadersFromHList HList xs
rest
ResponseHeader h x
MissingHeader `HCons` HList xs
rest -> HList xs -> [Header]
forall (hs :: [*]). GetHeadersFromHList hs => HList hs -> [Header]
getHeadersFromHList HList xs
rest
where
headerName :: CI ByteString
headerName = ByteString -> CI ByteString
forall s. FoldCase s => s -> CI s
CI.mk (ByteString -> CI ByteString)
-> (String -> ByteString) -> String -> CI ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> ByteString
pack (String -> CI ByteString) -> String -> CI ByteString
forall a b. (a -> b) -> a -> b
$ Proxy h -> String
forall (n :: Symbol) (proxy :: Symbol -> *).
KnownSymbol n =>
proxy n -> String
symbolVal (Proxy h
forall k (t :: k). Proxy t
Proxy :: Proxy h)
class hs where
:: Headers hs a -> [HTTP.Header]
instance GetHeaders' hs => GetHeaders (Headers hs a) where
getHeaders :: Headers hs a -> [Header]
getHeaders = Headers hs a -> [Header]
forall (hs :: [*]) a. GetHeaders' hs => Headers hs a -> [Header]
getHeaders'
instance GetHeaders' '[] where
getHeaders' :: Headers '[] a -> [Header]
getHeaders' Headers '[] a
_ = []
instance (KnownSymbol h, GetHeadersFromHList rest, ToHttpApiData v)
=> GetHeaders' (Header h v ': rest)
where
getHeaders' :: Headers (Header h v : rest) a -> [Header]
getHeaders' Headers (Header h v : rest) a
hs = HList (Header h v : rest) -> [Header]
forall (hs :: [*]). GetHeadersFromHList hs => HList hs -> [Header]
getHeadersFromHList (HList (Header h v : rest) -> [Header])
-> HList (Header h v : rest) -> [Header]
forall a b. (a -> b) -> a -> b
$ Headers (Header h v : rest) a -> HList (Header h v : rest)
forall (ls :: [*]) a. Headers ls a -> HList ls
getHeadersHList Headers (Header h v : rest) a
hs
class h v orig new
| h v orig -> new, new -> h, new -> v, new -> orig where
:: ResponseHeader h v -> orig -> new
instance {-# OVERLAPPING #-} ( KnownSymbol h, ToHttpApiData v )
=> AddHeader h v (Headers (fst ': rest) a) (Headers (Header h v ': fst ': rest) a) where
addOptionalHeader :: ResponseHeader h v
-> Headers (fst : rest) a -> Headers (Header h v : fst : rest) a
addOptionalHeader ResponseHeader h v
hdr (Headers a
resp HList (fst : rest)
heads) = a
-> HList (Header h v : fst : rest)
-> Headers (Header h v : fst : rest) a
forall (ls :: [*]) a. a -> HList ls -> Headers ls a
Headers a
resp (ResponseHeader h v
-> HList (fst : rest) -> HList (Header h v : fst : rest)
forall (h :: Symbol) x (xs :: [*]).
ResponseHeader h x -> HList xs -> HList (Header h x : xs)
HCons ResponseHeader h v
hdr HList (fst : rest)
heads)
instance {-# OVERLAPPABLE #-} ( KnownSymbol h, ToHttpApiData v
, new ~ (Headers '[Header h v] a) )
=> AddHeader h v a new where
addOptionalHeader :: ResponseHeader h v -> a -> new
addOptionalHeader ResponseHeader h v
hdr a
resp = a -> HList '[Header h v] -> Headers '[Header h v] a
forall (ls :: [*]) a. a -> HList ls -> Headers ls a
Headers a
resp (ResponseHeader h v -> HList '[] -> HList '[Header h v]
forall (h :: Symbol) x (xs :: [*]).
ResponseHeader h x -> HList xs -> HList (Header h x : xs)
HCons ResponseHeader h v
hdr HList '[]
HNil)
addHeader :: AddHeader h v orig new => v -> orig -> new
= ResponseHeader h v -> orig -> new
forall (h :: Symbol) v orig new.
AddHeader h v orig new =>
ResponseHeader h v -> orig -> new
addOptionalHeader (ResponseHeader h v -> orig -> new)
-> (v -> ResponseHeader h v) -> v -> orig -> new
forall b c a. (b -> c) -> (a -> b) -> a -> c
. v -> ResponseHeader h v
forall (sym :: Symbol) a. a -> ResponseHeader sym a
Header
noHeader :: AddHeader h v orig new => orig -> new
= ResponseHeader h v -> orig -> new
forall (h :: Symbol) v orig new.
AddHeader h v orig new =>
ResponseHeader h v -> orig -> new
addOptionalHeader ResponseHeader h v
forall (sym :: Symbol) a. ResponseHeader sym a
MissingHeader
class h a headers where
:: HList headers -> ResponseHeader h a
instance {-# OVERLAPPING #-} HasResponseHeader h a (Header h a ': rest) where
hlistLookupHeader :: HList (Header h a : rest) -> ResponseHeader h a
hlistLookupHeader (HCons ResponseHeader h x
ha HList xs
_) = ResponseHeader h a
ResponseHeader h x
ha
instance {-# OVERLAPPABLE #-} (HasResponseHeader h a rest) => HasResponseHeader h a (first ': rest) where
hlistLookupHeader :: HList (first : rest) -> ResponseHeader h a
hlistLookupHeader (HCons ResponseHeader h x
_ HList xs
hs) = HList xs -> ResponseHeader h a
forall (h :: Symbol) a (headers :: [*]).
HasResponseHeader h a headers =>
HList headers -> ResponseHeader h a
hlistLookupHeader HList xs
hs
lookupResponseHeader :: (HasResponseHeader h a headers)
=> Headers headers r -> ResponseHeader h a
= HList headers -> ResponseHeader h a
forall (h :: Symbol) a (headers :: [*]).
HasResponseHeader h a headers =>
HList headers -> ResponseHeader h a
hlistLookupHeader (HList headers -> ResponseHeader h a)
-> (Headers headers r -> HList headers)
-> Headers headers r
-> ResponseHeader h a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Headers headers r -> HList headers
forall (ls :: [*]) a. Headers ls a -> HList ls
getHeadersHList