@@ -27,14 +27,13 @@ module Servant.Client
2727#if !MIN_VERSION_base(4,8,0)
2828import Control.Applicative ((<$>))
2929#endif
30−import Control.Monad.Trans.Except
3130import Data.ByteString.Lazy (ByteString)
3231import Data.List
3332import Data.Proxy
3433import Data.String.Conversions
3534import Data.Text (unpack)
3635import GHC.TypeLits
37−import Network.HTTP.Client (Response, Manager)
36+import Network.HTTP.Client (Manager, Response)
3837import Network.HTTP.Media
3938import qualified Network.HTTP.Types as H
4039import qualified Network.HTTP.Types.Header as HTTP
@@ -54,19 +53,18 @@ import Servant.Common.Req
5453-- > myApi :: Proxy MyApi
5554-- > myApi = Proxy
5655-- >
57−-- > getAllBooks :: ExceptT String IO [Book]
58−-- > postNewBook :: Book -> ExceptT String IO Book
59−-- > (getAllBooks :<|> postNewBook) = client myApi host manager
60−-- > where host = BaseUrl Http "localhost" 8080
61−client :: HasClient layout => Proxy layout -> BaseUrl -> Manager -> Client layout
62−client p baseurl = clientWithRoute p defReq baseurl
56+-- > getAllBooks :: Manager -> BaseUrl -> ClientM [Book]
57+-- > postNewBook :: Book -> Manager -> BaseUrl -> ClientM Book
58+-- > (getAllBooks :<|> postNewBook) = client myApi
59+client :: HasClient layout => Proxy layout -> Client layout
60+client p = clientWithRoute p defReq
6361
6462-- | This class lets us define how each API combinator
6563-- influences the creation of an HTTP request. It's mostly
6664-- an internal class, you can just use 'client'.
6765class HasClient layout where
6866 type Client layout :: *
69− clientWithRoute :: Proxy layout -> Req -> BaseUrl -> Manager -> Client layout
67+ clientWithRoute :: Proxy layout -> Req -> Client layout
7068
7169
7270-- | A client querying function for @a ':<|>' b@ will actually hand you
@@ -79,15 +77,14 @@ class HasClient layout where
7977-- > myApi :: Proxy MyApi
8078-- > myApi = Proxy
8179-- >
82−-- > getAllBooks :: ExceptT String IO [Book]
83−-- > postNewBook :: Book -> ExceptT String IO Book
84−-- > (getAllBooks :<|> postNewBook) = client myApi host manager
85−-- > where host = BaseUrl Http "localhost" 8080
80+-- > getAllBooks :: Manager -> BaseUrl -> ClientM [Book]
81+-- > postNewBook :: Book -> Manager -> BaseUrl -> ClientM Book
82+-- > (getAllBooks :<|> postNewBook) = client myApi
8683instance (HasClient a, HasClient b) => HasClient (a :<|> b) where
8784 type Client (a :<|> b) = Client a :<|> Client b
88− clientWithRoute Proxy req baseurl manager =
89− clientWithRoute (Proxy :: Proxy a) req baseurl manager :<|>
90− clientWithRoute (Proxy :: Proxy b) req baseurl manager
85+ clientWithRoute Proxy req =
86+ clientWithRoute (Proxy :: Proxy a) req :<|>
87+ clientWithRoute (Proxy :: Proxy b) req
9188
9289-- | If you use a 'Capture' in one of your endpoints in your API,
9390-- the corresponding querying function will automatically take
@@ -105,9 +102,8 @@ instance (HasClient a, HasClient b) => HasClient (a :<|> b) where
105102-- > myApi :: Proxy MyApi
106103-- > myApi = Proxy
107104-- >
108−-- > getBook :: Text -> ExceptT String IO Book
109−-- > getBook = client myApi host manager
110−-- > where host = BaseUrl Http "localhost" 8080
105+-- > getBook :: Text -> Manager -> BaseUrl -> ClientM Book
106+-- > getBook = client myApi
111107-- > -- then you can just use "getBook" to query that endpoint
112108instance (KnownSymbol capture, ToHttpApiData a, HasClient sublayout)
113109 => HasClient (Capture capture a :> sublayout) where
@@ -115,11 +111,9 @@ instance (KnownSymbol capture, ToHttpApiData a, HasClient sublayout)
115111 type Client (Capture capture a :> sublayout) =
116112 a -> Client sublayout
117113
118− clientWithRoute Proxy req baseurl manager val =
114+ clientWithRoute Proxy req val =
119115 clientWithRoute (Proxy :: Proxy sublayout)
120116 (appendToPath p req)
121− baseurl
122− manager
123117
124118 where p = unpack (toUrlPiece val)
125119
@@ -127,16 +121,17 @@ instance OVERLAPPABLE_
127121 -- Note [Non-Empty Content Types]
128122 (MimeUnrender ct a, ReflectMethod method, cts' ~ (ct ': cts)
129123 ) => HasClient (Verb method status cts' a) where
130− type Client (Verb method status cts' a) = ExceptT ServantError IO a
131− clientWithRoute Proxy req baseurl manager =
132− snd <$> performRequestCT (Proxy :: Proxy ct) method req baseurl manager
124+ type Client (Verb method status cts' a) = Manager -> BaseUrl -> ClientM a
125+ clientWithRoute Proxy req manager baseurl =
126+ snd <$> performRequestCT (Proxy :: Proxy ct) method req manager baseurl
133127 where method = reflectMethod (Proxy :: Proxy method)
134128
135129instance OVERLAPPING_
136130 (ReflectMethod method) => HasClient (Verb method status cts NoContent) where
137− type Client (Verb method status cts NoContent) = ExceptT ServantError IO NoContent
138− clientWithRoute Proxy req baseurl manager =
139− performRequestNoBody method req baseurl manager >> return NoContent
131+ type Client (Verb method status cts NoContent)
132+ = Manager -> BaseUrl -> ClientM NoContent
133+ clientWithRoute Proxy req manager baseurl =
134+ performRequestNoBody method req manager baseurl >> return NoContent
140135 where method = reflectMethod (Proxy :: Proxy method)
141136
142137instance OVERLAPPING_
@@ -144,10 +139,10 @@ instance OVERLAPPING_
144139 ( MimeUnrender ct a, BuildHeadersTo ls, ReflectMethod method, cts' ~ (ct ': cts)
145140 ) => HasClient (Verb method status cts' (Headers ls a)) where
146141 type Client (Verb method status cts' (Headers ls a))
147− = ExceptT ServantError IO (Headers ls a)
148− clientWithRoute Proxy req baseurl manager = do
142+ = Manager -> BaseUrl -> ClientM (Headers ls a)
143+ clientWithRoute Proxy req manager baseurl = do
149144 let method = reflectMethod (Proxy :: Proxy method)
150− (hdrs, resp) <- performRequestCT (Proxy :: Proxy ct) method req baseurl manager
145+ (hdrs, resp) <- performRequestCT (Proxy :: Proxy ct) method req manager baseurl
151146 return $ Headers { getResponse = resp
152147 , getHeadersHList = buildHeadersTo hdrs
153148 }
@@ -156,10 +151,10 @@ instance OVERLAPPING_
156151 ( BuildHeadersTo ls, ReflectMethod method
157152 ) => HasClient (Verb method status cts (Headers ls NoContent)) where
158153 type Client (Verb method status cts (Headers ls NoContent))
159− = ExceptT ServantError IO (Headers ls NoContent)
160− clientWithRoute Proxy req baseurl manager = do
154+ = Manager -> BaseUrl -> ClientM (Headers ls NoContent)
155+ clientWithRoute Proxy req manager baseurl = do
161156 let method = reflectMethod (Proxy :: Proxy method)
162− hdrs <- performRequestNoBody method req baseurl manager
157+ hdrs <- performRequestNoBody method req manager baseurl
163158 return $ Headers { getResponse = NoContent
164159 , getHeadersHList = buildHeadersTo hdrs
165160 }
@@ -186,9 +181,8 @@ instance OVERLAPPING_
186181-- > myApi :: Proxy MyApi
187182-- > myApi = Proxy
188183-- >
189−-- > viewReferer :: Maybe Referer -> ExceptT String IO Book
190−-- > viewReferer = client myApi host
191−-- > where host = BaseUrl Http "localhost" 8080
184+-- > viewReferer :: Maybe Referer -> Manager -> BaseUrl -> ClientM Book
185+-- > viewReferer = client myApi
192186-- > -- then you can just use "viewRefer" to query that endpoint
193187-- > -- specifying Nothing or e.g Just "http://haskell.org/" as arguments
194188instance (KnownSymbol sym, ToHttpApiData a, HasClient sublayout)
@@ -197,14 +191,12 @@ instance (KnownSymbol sym, ToHttpApiData a, HasClient sublayout)
197191 type Client (Header sym a :> sublayout) =
198192 Maybe a -> Client sublayout
199193
200− clientWithRoute Proxy req baseurl manager mval =
194+ clientWithRoute Proxy req mval =
201195 clientWithRoute (Proxy :: Proxy sublayout)
202196 (maybe req
203197 (\value -> Servant.Common.Req.addHeader hname value req)
204198 mval
205199 )
206− baseurl
207− manager
208200
209201 where hname = symbolVal (Proxy :: Proxy sym)
210202
@@ -239,9 +231,8 @@ instance HasClient sublayout
239231-- > myApi :: Proxy MyApi
240232-- > myApi = Proxy
241233-- >
242−-- > getBooksBy :: Maybe Text -> ExceptT String IO [Book]
243−-- > getBooksBy = client myApi host
244−-- > where host = BaseUrl Http "localhost" 8080
234+-- > getBooksBy :: Maybe Text -> Manager -> BaseUrl -> ClientM [Book]
235+-- > getBooksBy = client myApi
245236-- > -- then you can just use "getBooksBy" to query that endpoint.
246237-- > -- 'getBooksBy Nothing' for all books
247238-- > -- 'getBooksBy (Just "Isaac Asimov")' to get all books by Isaac Asimov
@@ -252,14 +243,12 @@ instance (KnownSymbol sym, ToHttpApiData a, HasClient sublayout)
252243 Maybe a -> Client sublayout
253244
254245 -- if mparam = Nothing, we don't add it to the query string
255− clientWithRoute Proxy req baseurl manager mparam =
246+ clientWithRoute Proxy req mparam =
256247 clientWithRoute (Proxy :: Proxy sublayout)
257248 (maybe req
258249 (flip (appendToQueryString pname) req . Just)
259250 mparamText
260251 )
261− baseurl
262− manager
263252
264253 where pname = cs pname'
265254 pname' = symbolVal (Proxy :: Proxy sym)
@@ -286,9 +275,8 @@ instance (KnownSymbol sym, ToHttpApiData a, HasClient sublayout)
286275-- > myApi :: Proxy MyApi
287276-- > myApi = Proxy
288277-- >
289−-- > getBooksBy :: [Text] -> ExceptT String IO [Book]
290−-- > getBooksBy = client myApi host
291−-- > where host = BaseUrl Http "localhost" 8080
278+-- > getBooksBy :: [Text] -> Manager -> BaseUrl -> ClientM [Book]
279+-- > getBooksBy = client myApi
292280-- > -- then you can just use "getBooksBy" to query that endpoint.
293281-- > -- 'getBooksBy []' for all books
294282-- > -- 'getBooksBy ["Isaac Asimov", "Robert A. Heinlein"]'
@@ -299,13 +287,12 @@ instance (KnownSymbol sym, ToHttpApiData a, HasClient sublayout)
299287 type Client (QueryParams sym a :> sublayout) =
300288 [a] -> Client sublayout
301289
302− clientWithRoute Proxy req baseurl manager paramlist =
290+ clientWithRoute Proxy req paramlist =
303291 clientWithRoute (Proxy :: Proxy sublayout)
304292 (foldl' (\ req' -> maybe req' (flip (appendToQueryString pname) req' . Just))
305293 req
306294 paramlist'
307295 )
308− baseurl manager
309296
310297 where pname = cs pname'
311298 pname' = symbolVal (Proxy :: Proxy sym)
@@ -327,9 +314,8 @@ instance (KnownSymbol sym, ToHttpApiData a, HasClient sublayout)
327314-- > myApi :: Proxy MyApi
328315-- > myApi = Proxy
329316-- >
330−-- > getBooks :: Bool -> ExceptT String IO [Book]
331−-- > getBooks = client myApi host
332−-- > where host = BaseUrl Http "localhost" 8080
317+-- > getBooks :: Bool -> Manager -> BaseUrl -> ClientM [Book]
318+-- > getBooks = client myApi
333319-- > -- then you can just use "getBooks" to query that endpoint.
334320-- > -- 'getBooksBy False' for all books
335321-- > -- 'getBooksBy True' to only get _already published_ books
@@ -339,13 +325,12 @@ instance (KnownSymbol sym, HasClient sublayout)
339325 type Client (QueryFlag sym :> sublayout) =
340326 Bool -> Client sublayout
341327
342− clientWithRoute Proxy req baseurl manager flag =
328+ clientWithRoute Proxy req flag =
343329 clientWithRoute (Proxy :: Proxy sublayout)
344330 (if flag
345331 then appendToQueryString paramname Nothing req
346332 else req
347333 )
348− baseurl manager
349334
350335 where paramname = cs $ symbolVal (Proxy :: Proxy sym)
351336
@@ -353,11 +338,12 @@ instance (KnownSymbol sym, HasClient sublayout)
353338-- | Pick a 'Method' and specify where the server you want to query is. You get
354339-- back the full `Response`.
355340instance HasClient Raw where
356− type Client Raw = H.Method -> ExceptT ServantError IO (Int, ByteString, MediaType, [HTTP.Header], Response ByteString)
341+ type Client Raw
342+ = H.Method -> Manager -> BaseUrl -> ClientM (Int, ByteString, MediaType, [HTTP.Header], Response ByteString)
357343
358− clientWithRoute :: Proxy Raw -> Req -> BaseUrl -> Manager -> Client Raw
359− clientWithRoute Proxy req baseurl manager httpMethod = do
360− performRequest httpMethod req baseurl manager
344+ clientWithRoute :: Proxy Raw -> Req -> Client Raw
345+ clientWithRoute Proxy req httpMethod = do
346+ performRequest httpMethod req
361347
362348-- | If you use a 'ReqBody' in one of your endpoints in your API,
363349-- the corresponding querying function will automatically take
@@ -374,9 +360,8 @@ instance HasClient Raw where
374360-- > myApi :: Proxy MyApi
375361-- > myApi = Proxy
376362-- >
377−-- > addBook :: Book -> ExceptT String IO Book
378−-- > addBook = client myApi host manager
379−-- > where host = BaseUrl Http "localhost" 8080
363+-- > addBook :: Book -> Manager -> BaseUrl -> ClientM Book
364+-- > addBook = client myApi
380365-- > -- then you can just use "addBook" to query that endpoint
381366instance (MimeRender ct a, HasClient sublayout)
382367 => HasClient (ReqBody (ct ': cts) a :> sublayout) where
@@ -384,43 +369,41 @@ instance (MimeRender ct a, HasClient sublayout)
384369 type Client (ReqBody (ct ': cts) a :> sublayout) =
385370 a -> Client sublayout
386371
387− clientWithRoute Proxy req baseurl manager body =
372+ clientWithRoute Proxy req body =
388373 clientWithRoute (Proxy :: Proxy sublayout)
389374 (let ctProxy = Proxy :: Proxy ct
390375 in setRQBody (mimeRender ctProxy body)
391376 (contentType ctProxy)
392377 req
393378 )
394− baseurl manager
395379
396380-- | Make the querying function append @path@ to the request path.
397381instance (KnownSymbol path, HasClient sublayout) => HasClient (path :> sublayout) where
398382 type Client (path :> sublayout) = Client sublayout
399383
400− clientWithRoute Proxy req baseurl manager =
384+ clientWithRoute Proxy req =
401385 clientWithRoute (Proxy :: Proxy sublayout)
402386 (appendToPath p req)
403− baseurl manager
404387
405388 where p = symbolVal (Proxy :: Proxy path)
406389
407390instance HasClient api => HasClient (Vault :> api) where
408391 type Client (Vault :> api) = Client api
409392
410− clientWithRoute Proxy req baseurl manager =
411− clientWithRoute (Proxy :: Proxy api) req baseurl manager
393+ clientWithRoute Proxy req =
394+ clientWithRoute (Proxy :: Proxy api) req
412395
413396instance HasClient api => HasClient (RemoteHost :> api) where
414397 type Client (RemoteHost :> api) = Client api
415398
416− clientWithRoute Proxy req baseurl manager =
417− clientWithRoute (Proxy :: Proxy api) req baseurl manager
399+ clientWithRoute Proxy req =
400+ clientWithRoute (Proxy :: Proxy api) req
418401
419402instance HasClient api => HasClient (IsSecure :> api) where
420403 type Client (IsSecure :> api) = Client api
421404
422− clientWithRoute Proxy req baseurl manager =
423− clientWithRoute (Proxy :: Proxy api) req baseurl manager
405+ clientWithRoute Proxy req =
406+ clientWithRoute (Proxy :: Proxy api) req
424407
425408instance HasClient subapi =>
426409 HasClient (WithNamedContext name context subapi) where
@@ -433,16 +416,16 @@ instance ( HasClient api
433416 type Client (AuthProtect tag :> api)
434417 = AuthenticateReq (AuthProtect tag) -> Client api
435418
436− clientWithRoute Proxy req baseurl manager (AuthenticateReq (val,func)) =
437− clientWithRoute (Proxy :: Proxy api) (func val req) baseurl manager
419+ clientWithRoute Proxy req (AuthenticateReq (val,func)) =
420+ clientWithRoute (Proxy :: Proxy api) (func val req)
438421
439422-- * Basic Authentication
440423
441424instance HasClient api => HasClient (BasicAuth realm usr :> api) where
442425 type Client (BasicAuth realm usr :> api) = BasicAuthData -> Client api
443426
444− clientWithRoute Proxy req baseurl manager val =
445− clientWithRoute (Proxy :: Proxy api) (basicAuthReq val req) baseurl manager
427+ clientWithRoute Proxy req val =
428+ clientWithRoute (Proxy :: Proxy api) (basicAuthReq val req)
446429
447430
448431{- Note [Non-Empty Content Types]