{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE TypeApplications #-}
module Servant.Client.NamedArgs where
import Named ((:!), (:?), arg, argF, argDef, Name(..))
import Data.Text (pack, Text)
import Data.Functor.Identity (Identity)
import Data.List (foldl')
import Servant.API ((:>), SBoolI, ToHttpApiData, toQueryParam, toUrlPiece)
import Servant.API.Modifiers (FoldRequired)
import Servant.API.NamedArgs ( foldRequiredNamedArgument, NamedCapture', NamedFlag
, NamedParam, NamedParams, RequiredNamedArgument
, NamedCaptureAll, NamedHeader')
import Servant.Client.Core.Internal.HasClient (HasClient(..))
import Servant.Client.Core.Internal.Request ( appendToPath, appendToQueryString, Request
, addHeader)
import Data.String (fromString)
import GHC.TypeLits (KnownSymbol, symbolVal)
import Data.Proxy (Proxy(..))
instance (KnownSymbol name, ToHttpApiData a, HasClient m api)
=> HasClient m (NamedCapture' mods name a :> api) where
type Client m (NamedCapture' mods name a :> api) =
(name :! a) -> Client m api
clientWithRoute pm _ req (arg (Name @name) -> capture) =
clientWithRoute pm (Proxy @api) (appendToPath (toUrlPiece capture) req)
hoistClientMonad pm _ f cl = \a ->
hoistClientMonad pm (Proxy @api) f (cl a)
instance (KnownSymbol name, ToHttpApiData a, HasClient m api)
=> HasClient m (NamedCaptureAll name a :> api) where
type Client m (NamedCaptureAll name a :> api) =
(name :? [a]) -> Client m api
clientWithRoute pm _ req (argDef (Name @name) [] -> captures) =
clientWithRoute pm (Proxy @api) (foldl' (flip appendToPath) req ps)
where
ps = map toUrlPiece captures
hoistClientMonad pm _ f cl = \as ->
hoistClientMonad pm (Proxy @api) f (cl as)
instance (KnownSymbol name, HasClient m api)
=> HasClient m (NamedFlag name :> api) where
type Client m (NamedFlag name :> api) =
(name :? Bool) -> Client m api
clientWithRoute pm _ req (argDef (Name @name) False -> mflag) =
clientWithRoute pm (Proxy @api) $
if mflag
then appendToQueryString pname Nothing req
else req
where
pname :: Text
pname = pack $ symbolVal (Proxy @name)
hoistClientMonad pm _ f cl = \b ->
hoistClientMonad pm (Proxy @api) f (cl b)
instance (KnownSymbol name, ToHttpApiData a, HasClient m api, SBoolI (FoldRequired mods))
=> HasClient m (NamedHeader' mods name a :> api) where
type Client m (NamedHeader' mods name a :> api) =
RequiredNamedArgument mods name a -> Client m api
clientWithRoute pm _ req mval =
clientWithRoute pm (Proxy @api) $
foldRequiredNamedArgument @mods @name
add
(maybe req add)
mval
where
add :: a -> Request
add value = addHeader hname value req
hname = fromString $ symbolVal (Proxy @name)
hoistClientMonad pm _ f cl = \a ->
hoistClientMonad pm (Proxy @api) f (cl a)
instance (KnownSymbol name, ToHttpApiData a, HasClient m api, SBoolI (FoldRequired mods))
=> HasClient m (NamedParam mods name a :> api) where
type Client m (NamedParam mods name a :> api) =
RequiredNamedArgument mods name a -> Client m api
clientWithRoute pm _ req mparam =
clientWithRoute pm (Proxy @api) $
foldRequiredNamedArgument @mods @name
add
(maybe req add)
mparam
where
add :: a -> Request
add param = appendToQueryString pname (Just $ toQueryParam param) req
pname :: Text
pname = pack $ symbolVal (Proxy @name)
hoistClientMonad pm _ f cl = \a ->
hoistClientMonad pm (Proxy @api) f (cl a)
instance (KnownSymbol name, ToHttpApiData a, HasClient m api)
=> HasClient m (NamedParams name a :> api) where
type Client m (NamedParams name a :> api) =
(name :? [a]) -> Client m api
clientWithRoute pm _ req (argDef (Name @name) [] -> mparams) =
clientWithRoute pm (Proxy @api) $
case mparams of
[] -> req
ls -> foldl'
(\req' param -> appendToQueryString pname (Just $ toQueryParam param) req')
req
ls
where
pname :: Text
pname = pack $ symbolVal (Proxy :: Proxy name)
hoistClientMonad pm _ f cl = \as ->
hoistClientMonad pm (Proxy @api) f (cl as)