@@ -6,6 +6,7 @@
6{-# LANGUAGE MultiParamTypeClasses #-}
6{-# LANGUAGE MultiParamTypeClasses #-}
7{-# LANGUAGE OverloadedStrings #-}
7{-# LANGUAGE OverloadedStrings #-}
8{-# LANGUAGE PolyKinds #-}
8{-# LANGUAGE PolyKinds #-}
9+{-# LANGUAGE RankNTypes #-}
9{-# LANGUAGE ScopedTypeVariables #-}
10{-# LANGUAGE ScopedTypeVariables #-}
10{-# LANGUAGE TypeFamilies #-}
11{-# LANGUAGE TypeFamilies #-}
11{-# LANGUAGE TypeOperators #-}
12{-# LANGUAGE TypeOperators #-}
@@ -35,7 +36,8 @@ import Servant.API ((:<|>) ((:<|>)), (:>),
35 BuildFromStream (..),
36 BuildFromStream (..),
36 ByteStringParser (..),
37 ByteStringParser (..),
37 Capture', CaptureAll,
38 Capture', CaptureAll,
39+ Description, DynHeaders,
38− Description, EmptyAPI,
40+ EmptyAPI,
39 FramingUnrender (..),
41 FramingUnrender (..),
40 Header', Headers (..),
42 Header', Headers (..),
41 HttpVersion, IsSecure,
43 HttpVersion, IsSecure,
@@ -97,6 +99,12 @@ clientIn p pm = clientWithRoute pm p defaultRequest
97class RunClient m => HasClient m api where
99class RunClient m => HasClient m api where
98 type Client (m :: * -> *) (api :: *) :: *
100 type Client (m :: * -> *) (api :: *) :: *
99 clientWithRoute :: Proxy m -> Proxy api -> Request -> Client m api
101 clientWithRoute :: Proxy m -> Proxy api -> Request -> Client m api
105+ -> (forall x. mon x -> mon' x)
102-- | A client querying function for @a ':<|>' b@ will actually hand you
110-- | A client querying function for @a ':<|>' b@ will actually hand you
@@ -118,6 +126,10 @@ instance (HasClient m a, HasClient m b) => HasClient m (a :<|> b) where
118 clientWithRoute pm (Proxy :: Proxy a) req :<|>
126 clientWithRoute pm (Proxy :: Proxy a) req :<|>
119 clientWithRoute pm (Proxy :: Proxy b) req
127 clientWithRoute pm (Proxy :: Proxy b) req
129+ hoistClientMonad pm _ f (ca :<|> cb) =
130+ hoistClientMonad pm (Proxy :: Proxy a) f ca :<|>
131+ hoistClientMonad pm (Proxy :: Proxy b) f cb
121-- | Singleton type representing a client for an empty API.
133-- | Singleton type representing a client for an empty API.
122data EmptyClient = EmptyClient deriving (Eq, Show, Bounded, Enum)
134data EmptyClient = EmptyClient deriving (Eq, Show, Bounded, Enum)
@@ -134,6 +146,7 @@ data EmptyClient = EmptyClient deriving (Eq, Show, Bounded, Enum)
134instance RunClient m => HasClient m EmptyAPI where
146instance RunClient m => HasClient m EmptyAPI where
135 type Client m EmptyAPI = EmptyClient
147 type Client m EmptyAPI = EmptyClient
136 clientWithRoute _pm Proxy _ = EmptyClient
148 clientWithRoute _pm Proxy _ = EmptyClient
149+ hoistClientMonad _ _ _ EmptyClient = EmptyClient
138-- | If you use a 'Capture' in one of your endpoints in your API,
151-- | If you use a 'Capture' in one of your endpoints in your API,
139-- the corresponding querying function will automatically take
152-- the corresponding querying function will automatically take
@@ -166,6 +179,9 @@ instance (KnownSymbol capture, ToHttpApiData a, HasClient m api)
167 where p = (toUrlPiece val)
180 where p = (toUrlPiece val)
182+ hoistClientMonad pm _ f cl = \a ->
183+ hoistClientMonad pm (Proxy :: Proxy api) f (cl a)
169-- | If you use a 'CaptureAll' in one of your endpoints in your API,
185-- | If you use a 'CaptureAll' in one of your endpoints in your API,
170-- the corresponding querying function will automatically take an
186-- the corresponding querying function will automatically take an
171-- additional argument of a list of the type specified by your
187-- additional argument of a list of the type specified by your
@@ -198,6 +214,9 @@ instance (KnownSymbol capture, ToHttpApiData a, HasClient m sublayout)
199 where ps = map (toUrlPiece) vals
215 where ps = map (toUrlPiece) vals
217+ hoistClientMonad pm _ f cl = \as ->
218+ hoistClientMonad pm (Proxy :: Proxy sublayout) f (cl as)
201instance OVERLAPPABLE_
220instance OVERLAPPABLE_
202 -- Note [Non-Empty Content Types]
221 -- Note [Non-Empty Content Types]
203 ( RunClient m, MimeUnrender ct a, ReflectMethod method, cts' ~ (ct ': cts)
222 ( RunClient m, MimeUnrender ct a, ReflectMethod method, cts' ~ (ct ': cts)
@@ -213,6 +232,8 @@ instance OVERLAPPABLE_
213 accept = contentTypes (Proxy :: Proxy ct)
232 accept = contentTypes (Proxy :: Proxy ct)
214 method = reflectMethod (Proxy :: Proxy method)
233 method = reflectMethod (Proxy :: Proxy method)
235+ hoistClientMonad _ _ f ma = f ma
216instance OVERLAPPING_
237instance OVERLAPPING_
217 ( RunClient m, ReflectMethod method
238 ( RunClient m, ReflectMethod method
218 ) => HasClient m (Verb method status cts NoContent) where
239 ) => HasClient m (Verb method status cts NoContent) where
@@ -223,6 +244,8 @@ instance OVERLAPPING_
223 return NoContent
244 return NoContent
224 where method = reflectMethod (Proxy :: Proxy method)
245 where method = reflectMethod (Proxy :: Proxy method)
247+ hoistClientMonad _ _ f ma = f ma
226instance OVERLAPPING_
249instance OVERLAPPING_
227 -- Note [Non-Empty Content Types]
250 -- Note [Non-Empty Content Types]
228 ( RunClient m, MimeUnrender ct a, BuildHeadersTo ls
251 ( RunClient m, MimeUnrender ct a, BuildHeadersTo ls
@@ -244,6 +267,8 @@ instance OVERLAPPING_
244 where method = reflectMethod (Proxy :: Proxy method)
267 where method = reflectMethod (Proxy :: Proxy method)
245 accept = contentTypes (Proxy :: Proxy ct)
268 accept = contentTypes (Proxy :: Proxy ct)
270+ hoistClientMonad _ _ f ma = f ma
247instance OVERLAPPING_
272instance OVERLAPPING_
248 ( RunClient m, BuildHeadersTo ls, ReflectMethod method
273 ( RunClient m, BuildHeadersTo ls, ReflectMethod method
249 ) => HasClient m (Verb method status cts (Headers ls NoContent)) where
274 ) => HasClient m (Verb method status cts (Headers ls NoContent)) where
@@ -256,6 +281,38 @@ instance OVERLAPPING_
256 , getHeadersHList = buildHeadersTo . toList $ responseHeaders response
281 , getHeadersHList = buildHeadersTo . toList $ responseHeaders response
284+ hoistClientMonad _ _ f ma = f ma
286+instance OVERLAPPING_
287+ ( RunClient m, MimeUnrender ct a, ReflectMethod method, cts' ~ (ct ': cts)
288+ ) => HasClient m (Verb method status cts' (DynHeaders a)) where
289+ type Client m (Verb method status cts' (DynHeaders a)) = m a
290+ clientWithRoute _pm Proxy req = do
291+ response <- runRequest req
292+ { requestMethod = method
293+ , requestAccept = fromList $ toList accept
295+ case mimeUnrender (Proxy :: Proxy ct) $ responseBody response of
296+ Left err -> throwServantError $ DecodeFailure (pack err) response
297+ Right val -> return val
299+ where method = reflectMethod (Proxy :: Proxy method)
300+ accept = contentTypes (Proxy :: Proxy ct)
302+ hoistClientMonad _ _ f ma = f ma
304+instance OVERLAPPING_
305+ ( RunClient m, ReflectMethod method
306+ ) => HasClient m (Verb method status cts (DynHeaders NoContent)) where
307+ type Client m (Verb method status cts (DynHeaders NoContent)) = m NoContent
308+ clientWithRoute _pm Proxy req = do
309+ response <- runRequest req { requestMethod = method }
312+ where method = reflectMethod (Proxy :: Proxy method)
314+ hoistClientMonad _ _ f ma = f ma
259instance OVERLAPPABLE_
316instance OVERLAPPABLE_
260 ( RunClient m, MimeUnrender ct a, ReflectMethod method,
317 ( RunClient m, MimeUnrender ct a, ReflectMethod method,
261 FramingUnrender framing a, BuildFromStream a (f a)
318 FramingUnrender framing a, BuildFromStream a (f a)
@@ -304,6 +361,7 @@ instance OVERLAPPABLE_
304 processResult (Left err, _) = Just (Left err)
361 processResult (Left err, _) = Just (Left err)
364+ hoistClientMonad _ _ f ma = f ma
308-- | If you use a 'Header' in one of your endpoints in your API,
366-- | If you use a 'Header' in one of your endpoints in your API,
309-- the corresponding querying function will automatically take
367-- the corresponding querying function will automatically take
@@ -345,6 +403,9 @@ instance (KnownSymbol sym, ToHttpApiData a, HasClient m api, SBoolI (FoldRequire
345 add :: a -> Request
403 add :: a -> Request
346 add value = addHeader hname value req
404 add value = addHeader hname value req
406+ hoistClientMonad pm _ f cl = \arg ->
407+ hoistClientMonad pm (Proxy :: Proxy api) f (cl arg)
348-- | Using a 'HttpVersion' combinator in your API doesn't affect the client
409-- | Using a 'HttpVersion' combinator in your API doesn't affect the client
349-- functions.
410-- functions.
350instance HasClient m api
411instance HasClient m api
@@ -356,18 +417,24 @@ instance HasClient m api
356 clientWithRoute pm Proxy =
417 clientWithRoute pm Proxy =
357 clientWithRoute pm (Proxy :: Proxy api)
418 clientWithRoute pm (Proxy :: Proxy api)
420+ hoistClientMonad pm _ f cl = hoistClientMonad pm (Proxy :: Proxy api) f cl
359-- | Ignore @'Summary'@ in client functions.
422-- | Ignore @'Summary'@ in client functions.
360instance HasClient m api => HasClient m (Summary desc :> api) where
423instance HasClient m api => HasClient m (Summary desc :> api) where
361 type Client m (Summary desc :> api) = Client m api
424 type Client m (Summary desc :> api) = Client m api
363 clientWithRoute pm _ = clientWithRoute pm (Proxy :: Proxy api)
426 clientWithRoute pm _ = clientWithRoute pm (Proxy :: Proxy api)
428+ hoistClientMonad pm _ f cl = hoistClientMonad pm (Proxy :: Proxy api) f cl
365-- | Ignore @'Description'@ in client functions.
430-- | Ignore @'Description'@ in client functions.
366instance HasClient m api => HasClient m (Description desc :> api) where
431instance HasClient m api => HasClient m (Description desc :> api) where
367 type Client m (Description desc :> api) = Client m api
432 type Client m (Description desc :> api) = Client m api
369 clientWithRoute pm _ = clientWithRoute pm (Proxy :: Proxy api)
434 clientWithRoute pm _ = clientWithRoute pm (Proxy :: Proxy api)
436+ hoistClientMonad pm _ f cl = hoistClientMonad pm (Proxy :: Proxy api) f cl
371-- | If you use a 'QueryParam' in one of your endpoints in your API,
438-- | If you use a 'QueryParam' in one of your endpoints in your API,
372-- the corresponding querying function will automatically take
439-- the corresponding querying function will automatically take
373-- an additional argument of the type specified by your 'QueryParam',
440-- an additional argument of the type specified by your 'QueryParam',
@@ -410,6 +477,9 @@ instance (KnownSymbol sym, ToHttpApiData a, HasClient m api, SBoolI (FoldRequire
410 pname :: Text
477 pname :: Text
411 pname = pack $ symbolVal (Proxy :: Proxy sym)
478 pname = pack $ symbolVal (Proxy :: Proxy sym)
480+ hoistClientMonad pm _ f cl = \arg ->
481+ hoistClientMonad pm (Proxy :: Proxy api) f (cl arg)
413-- | If you use a 'QueryParams' in one of your endpoints in your API,
483-- | If you use a 'QueryParams' in one of your endpoints in your API,
414-- the corresponding querying function will automatically take
484-- the corresponding querying function will automatically take
415-- an additional argument, a list of values of the type specified
485-- an additional argument, a list of values of the type specified
@@ -453,6 +523,9 @@ instance (KnownSymbol sym, ToHttpApiData a, HasClient m api)
453 where pname = pack $ symbolVal (Proxy :: Proxy sym)
523 where pname = pack $ symbolVal (Proxy :: Proxy sym)
454 paramlist' = map (Just . toQueryParam) paramlist
524 paramlist' = map (Just . toQueryParam) paramlist
526+ hoistClientMonad pm _ f cl = \as ->
527+ hoistClientMonad pm (Proxy :: Proxy api) f (cl as)
456-- | If you use a 'QueryFlag' in one of your endpoints in your API,
529-- | If you use a 'QueryFlag' in one of your endpoints in your API,
457-- the corresponding querying function will automatically take
530-- the corresponding querying function will automatically take
458-- an additional 'Bool' argument.
531-- an additional 'Bool' argument.
@@ -489,6 +562,8 @@ instance (KnownSymbol sym, HasClient m api)
490 where paramname = pack $ symbolVal (Proxy :: Proxy sym)
563 where paramname = pack $ symbolVal (Proxy :: Proxy sym)
565+ hoistClientMonad pm _ f cl = \b ->
566+ hoistClientMonad pm (Proxy :: Proxy api) f (cl b)
493-- | Pick a 'Method' and specify where the server you want to query is. You get
568-- | Pick a 'Method' and specify where the server you want to query is. You get
494-- back the full `Response`.
569-- back the full `Response`.
@@ -500,6 +575,8 @@ instance RunClient m => HasClient m Raw where
500 clientWithRoute _pm Proxy req httpMethod = do
575 clientWithRoute _pm Proxy req httpMethod = do
501 runRequest req { requestMethod = httpMethod }
576 runRequest req { requestMethod = httpMethod }
578+ hoistClientMonad _ _ f cl = \meth -> f (cl meth)
503-- | If you use a 'ReqBody' in one of your endpoints in your API,
580-- | If you use a 'ReqBody' in one of your endpoints in your API,
504-- the corresponding querying function will automatically take
581-- the corresponding querying function will automatically take
505-- an additional argument of the type specified by your 'ReqBody'.
582-- an additional argument of the type specified by your 'ReqBody'.
@@ -533,6 +610,9 @@ instance (MimeRender ct a, HasClient m api)
613+ hoistClientMonad pm _ f cl = \a ->
614+ hoistClientMonad pm (Proxy :: Proxy api) f (cl a)
536-- | Make the querying function append @path@ to the request path.
616-- | Make the querying function append @path@ to the request path.
537instance (KnownSymbol path, HasClient m api) => HasClient m (path :> api) where
617instance (KnownSymbol path, HasClient m api) => HasClient m (path :> api) where
538 type Client m (path :> api) = Client m api
618 type Client m (path :> api) = Client m api
@@ -543,30 +623,40 @@ instance (KnownSymbol path, HasClient m api) => HasClient m (path :> api) where
544 where p = pack $ symbolVal (Proxy :: Proxy path)
624 where p = pack $ symbolVal (Proxy :: Proxy path)
626+ hoistClientMonad pm _ f cl = hoistClientMonad pm (Proxy :: Proxy api) f cl
546instance HasClient m api => HasClient m (Vault :> api) where
628instance HasClient m api => HasClient m (Vault :> api) where
547 type Client m (Vault :> api) = Client m api
629 type Client m (Vault :> api) = Client m api
549 clientWithRoute pm Proxy req =
631 clientWithRoute pm Proxy req =
550 clientWithRoute pm (Proxy :: Proxy api) req
632 clientWithRoute pm (Proxy :: Proxy api) req
634+ hoistClientMonad pm _ f cl = hoistClientMonad pm (Proxy :: Proxy api) f cl
552instance HasClient m api => HasClient m (RemoteHost :> api) where
636instance HasClient m api => HasClient m (RemoteHost :> api) where
553 type Client m (RemoteHost :> api) = Client m api
637 type Client m (RemoteHost :> api) = Client m api
555 clientWithRoute pm Proxy req =
639 clientWithRoute pm Proxy req =
556 clientWithRoute pm (Proxy :: Proxy api) req
640 clientWithRoute pm (Proxy :: Proxy api) req
642+ hoistClientMonad pm _ f cl = hoistClientMonad pm (Proxy :: Proxy api) f cl
558instance HasClient m api => HasClient m (IsSecure :> api) where
644instance HasClient m api => HasClient m (IsSecure :> api) where
559 type Client m (IsSecure :> api) = Client m api
645 type Client m (IsSecure :> api) = Client m api
561 clientWithRoute pm Proxy req =
647 clientWithRoute pm Proxy req =
562 clientWithRoute pm (Proxy :: Proxy api) req
648 clientWithRoute pm (Proxy :: Proxy api) req
650+ hoistClientMonad pm _ f cl = hoistClientMonad pm (Proxy :: Proxy api) f cl
564instance HasClient m subapi =>
652instance HasClient m subapi =>
565 HasClient m (WithNamedContext name context subapi) where
653 HasClient m (WithNamedContext name context subapi) where
567 type Client m (WithNamedContext name context subapi) = Client m subapi
655 type Client m (WithNamedContext name context subapi) = Client m subapi
568 clientWithRoute pm Proxy = clientWithRoute pm (Proxy :: Proxy subapi)
656 clientWithRoute pm Proxy = clientWithRoute pm (Proxy :: Proxy subapi)
658+ hoistClientMonad pm _ f cl = hoistClientMonad pm (Proxy :: Proxy subapi) f cl
570instance ( HasClient m api
660instance ( HasClient m api
571 ) => HasClient m (AuthProtect tag :> api) where
661 ) => HasClient m (AuthProtect tag :> api) where
572 type Client m (AuthProtect tag :> api)
662 type Client m (AuthProtect tag :> api)
@@ -575,6 +665,9 @@ instance ( HasClient m api
575 clientWithRoute pm Proxy req (AuthenticatedRequest (val,func)) =
665 clientWithRoute pm Proxy req (AuthenticatedRequest (val,func)) =
576 clientWithRoute pm (Proxy :: Proxy api) (func val req)
666 clientWithRoute pm (Proxy :: Proxy api) (func val req)
668+ hoistClientMonad pm _ f cl = \authreq ->
669+ hoistClientMonad pm (Proxy :: Proxy api) f (cl authreq)
578-- * Basic Authentication
671-- * Basic Authentication
580instance HasClient m api => HasClient m (BasicAuth realm usr :> api) where
673instance HasClient m api => HasClient m (BasicAuth realm usr :> api) where
@@ -583,6 +676,9 @@ instance HasClient m api => HasClient m (BasicAuth realm usr :> api) where
583 clientWithRoute pm Proxy req val =
676 clientWithRoute pm Proxy req val =
584 clientWithRoute pm (Proxy :: Proxy api) (basicAuthReq val req)
677 clientWithRoute pm (Proxy :: Proxy api) (basicAuthReq val req)
679+ hoistClientMonad pm _ f cl = \bauth ->
680+ hoistClientMonad pm (Proxy :: Proxy api) f (cl bauth)
587{- Note [Non-Empty Content Types]
683{- Note [Non-Empty Content Types]
588~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
684~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~