@@ -1,15 +1,16 @@
1−{-# LANGUAGE AllowAmbiguousTypes #-}
2−{-# LANGUAGE CPP #-}
3−{-# LANGUAGE DataKinds #-}
4−{-# LANGUAGE FlexibleContexts #-}
5−{-# LANGUAGE FlexibleInstances #-}
6−{-# LANGUAGE InstanceSigs #-}
7−{-# LANGUAGE OverloadedStrings #-}
8−{-# LANGUAGE PolyKinds #-}
9−{-# LANGUAGE ScopedTypeVariables #-}
10−{-# LANGUAGE TypeFamilies #-}
11−{-# LANGUAGE TypeOperators #-}
12−{-# LANGUAGE UndecidableInstances #-}
1+{-# LANGUAGE AllowAmbiguousTypes #-}
2+{-# LANGUAGE CPP #-}
3+{-# LANGUAGE DataKinds #-}
4+{-# LANGUAGE FlexibleContexts #-}
5+{-# LANGUAGE FlexibleInstances #-}
6+{-# LANGUAGE InstanceSigs #-}
7+{-# LANGUAGE MultiParamTypeClasses #-}
8+{-# LANGUAGE OverloadedStrings #-}
9+{-# LANGUAGE PolyKinds #-}
10+{-# LANGUAGE ScopedTypeVariables #-}
11+{-# LANGUAGE TypeFamilies #-}
12+{-# LANGUAGE TypeOperators #-}
13+{-# LANGUAGE UndecidableInstances #-}
1314
1415#include "overlapping-compat.h"
1516-- | This module provides 'client' which can automatically generate
@@ -62,15 +63,15 @@ import Servant.Common.Req
6263-- > getAllBooks :: ClientM [Book]
6364-- > postNewBook :: Book -> ClientM Book
6465-- > (getAllBooks :<|> postNewBook) = client myApi
65−client :: HasClient api => Proxy api -> Client m api
66−client p = clientWithRoute p defReq
66+client :: HasClient m api => Proxy m -> Proxy api -> Client m api
67+client pm p = clientWithRoute pm p defReq
6768
6869-- | This class lets us define how each API combinator
6970-- influences the creation of an HTTP request. It's mostly
7071-- an internal class, you can just use 'client'.
71−class HasClient api where
72+class HasClient m api where
7273 type Client (m :: * -> *) (api :: *) :: *
73− clientWithRoute :: Proxy api -> Req -> Client m api
74+ clientWithRoute :: Proxy m -> Proxy api -> Req -> Client m api
7475
7576
7677-- | A client querying function for @a ':<|>' b@ will actually hand you
@@ -86,11 +87,11 @@ class HasClient api where
8687-- > getAllBooks :: ClientM [Book]
8788-- > postNewBook :: Book -> ClientM Book
8889-- > (getAllBooks :<|> postNewBook) = client myApi
89−instance (HasClient a, HasClient b) => HasClient (a :<|> b) where
90+instance (HasClient m a, HasClient m b) => HasClient m (a :<|> b) where
9091 type Client m (a :<|> b) = Client m a :<|> Client m b
91− clientWithRoute Proxy req =
92− clientWithRoute (Proxy :: Proxy a) req :<|>
93− clientWithRoute (Proxy :: Proxy b) req
92+ clientWithRoute pm Proxy req =
93+ clientWithRoute pm (Proxy :: Proxy a) req :<|>
94+ clientWithRoute pm (Proxy :: Proxy b) req
9495
9596-- | Singleton type representing a client for an empty API.
9697data EmptyClient = EmptyClient deriving (Eq, Show, Bounded, Enum)
@@ -105,9 +106,9 @@ data EmptyClient = EmptyClient deriving (Eq, Show, Bounded, Enum)
105106-- >
106107-- > getAllBooks :: ClientM [Book]
107108-- > (getAllBooks :<|> EmptyClient) = client myApi
108−instance HasClient EmptyAPI where
109+instance HasClient m EmptyAPI where
109110 type Client m EmptyAPI = EmptyClient
110− clientWithRoute Proxy _ = EmptyClient
111+ clientWithRoute pm Proxy _ = EmptyClient
111112
112113-- | If you use a 'Capture' in one of your endpoints in your API,
113114-- the corresponding querying function will automatically take
@@ -128,14 +129,14 @@ instance HasClient EmptyAPI where
128129-- > getBook :: Text -> ClientM Book
129130-- > getBook = client myApi
130131-- > -- then you can just use "getBook" to query that endpoint
131−instance (KnownSymbol capture, ToHttpApiData a, HasClient api)
132− => HasClient (Capture capture a :> api) where
132+instance (KnownSymbol capture, ToHttpApiData a, HasClient m api)
133+ => HasClient m (Capture capture a :> api) where
133134
134135 type Client m (Capture capture a :> api) =
135136 a -> Client m api
136137
137− clientWithRoute Proxy req val =
138− clientWithRoute (Proxy :: Proxy api)
138+ clientWithRoute pm Proxy req val =
139+ clientWithRoute pm (Proxy :: Proxy api)
139140 (appendToPath p req)
140141
141142 where p = unpack (toUrlPiece val)
@@ -160,14 +161,14 @@ instance (KnownSymbol capture, ToHttpApiData a, HasClient api)
160161-- > getSourceFile :: [Text] -> ClientM SourceFile
161162-- > getSourceFile = client myApi
162163-- > -- then you can use "getSourceFile" to query that endpoint
163−instance (KnownSymbol capture, ToHttpApiData a, HasClient sublayout)
164− => HasClient (CaptureAll capture a :> sublayout) where
164+instance (KnownSymbol capture, ToHttpApiData a, HasClient m sublayout)
165+ => HasClient m (CaptureAll capture a :> sublayout) where
165166
166167 type Client m (CaptureAll capture a :> sublayout) =
167168 [a] -> Client m sublayout
168169
169− clientWithRoute Proxy req vals =
170− clientWithRoute (Proxy :: Proxy sublayout)
170+ clientWithRoute pm Proxy req vals =
171+ clientWithRoute pm (Proxy :: Proxy sublayout)
171172 (foldl' (flip appendToPath) req ps)
172173
173174 where ps = map (unpack . toUrlPiece) vals
@@ -175,27 +176,31 @@ instance (KnownSymbol capture, ToHttpApiData a, HasClient sublayout)
175176instance OVERLAPPABLE_
176177 -- Note [Non-Empty Content Types]
177178 (RunClient m ct ([H.Header], a), MimeUnrender ct a, ReflectMethod method, cts' ~ (ct ': cts)
178− ) => HasClient (Verb method status cts' a) where
179+ ) => HasClient m (Verb method status cts' a) where
179180 type Client m (Verb method status cts' a) = m a
180− clientWithRoute Proxy req = do
181− snd <$> runRequest (Proxy :: Proxy ct) method req
181+ clientWithRoute pm Proxy req = do
182+ (_hdrs, a) :: ([H.Header], a) <- runRequest (Proxy :: Proxy ct) method req
183+ return a
182184 where method = reflectMethod (Proxy :: Proxy method)
183185
184186instance OVERLAPPING_
185− (RunClient m NoContent [H.Header], ReflectMethod method) => HasClient (Verb method status cts NoContent) where
187+ ( RunClient m NoContent [HTTP.Header]
188+ , ReflectMethod method) => HasClient m (Verb method status cts NoContent) where
186189 type Client m (Verb method status cts NoContent)
187190 = m NoContent
188− clientWithRoute Proxy req = do
189− runRequest (Proxy :: Proxy NoContent) method req >> return NoContent
191+ clientWithRoute pm Proxy req = do
192+ _hdrs :: [H.Header] <- runRequest (Proxy :: Proxy NoContent) method req
193+ return NoContent
190194 where method = reflectMethod (Proxy :: Proxy method)
191195
192196instance OVERLAPPING_
193197 -- Note [Non-Empty Content Types]
194− ( RunClient m ct ([H.Header], a), MimeUnrender ct a, BuildHeadersTo ls, ReflectMethod method, cts' ~ (ct ': cts)
195− ) => HasClient (Verb method status cts' (Headers ls a)) where
198+ ( RunClient m ct ([H.Header], a)
199+ , MimeUnrender ct a, BuildHeadersTo ls, ReflectMethod method, cts' ~ (ct ': cts)
200+ ) => HasClient m (Verb method status cts' (Headers ls a)) where
196201 type Client m (Verb method status cts' (Headers ls a))
197202 = m (Headers ls a)
198− clientWithRoute Proxy req = do
203+ clientWithRoute pm Proxy req = do
199204 let method = reflectMethod (Proxy :: Proxy method)
200205 (hdrs, resp) <- runRequest (Proxy :: Proxy ct) method req
201206 return $ Headers { getResponse = resp
@@ -203,13 +208,14 @@ instance OVERLAPPING_
203208 }
204209
205210instance OVERLAPPING_
206− ( RunClient m NoContent [H.Header], BuildHeadersTo ls, ReflectMethod method
207− ) => HasClient (Verb method status cts (Headers ls NoContent)) where
211+ ( RunClient m NoContent [H.Header]
212+ , BuildHeadersTo ls, ReflectMethod method
213+ ) => HasClient m (Verb method status cts (Headers ls NoContent)) where
208214 type Client m (Verb method status cts (Headers ls NoContent))
209215 = m (Headers ls NoContent)
210− clientWithRoute Proxy req = do
216+ clientWithRoute pm Proxy req = do
211217 let method = reflectMethod (Proxy :: Proxy method)
212− hdrs <- runRequest method req
218+ hdrs <- runRequest (Proxy :: Proxy NoContent) method req
213219 return $ Headers { getResponse = NoContent
214220 , getHeadersHList = buildHeadersTo hdrs
215221 }
@@ -240,14 +246,14 @@ instance OVERLAPPING_
240246-- > viewReferer = client myApi
241247-- > -- then you can just use "viewRefer" to query that endpoint
242248-- > -- specifying Nothing or e.g Just "http://haskell.org/" as arguments
243−instance (KnownSymbol sym, ToHttpApiData a, HasClient api)
244− => HasClient (Header sym a :> api) where
249+instance (KnownSymbol sym, ToHttpApiData a, HasClient m api)
250+ => HasClient m (Header sym a :> api) where
245251
246252 type Client m (Header sym a :> api) =
247253 Maybe a -> Client m api
248254
249− clientWithRoute Proxy req mval =
250− clientWithRoute (Proxy :: Proxy api)
255+ clientWithRoute pm Proxy req mval =
256+ clientWithRoute pm (Proxy :: Proxy api)
251257 (maybe req
252258 (\value -> Servant.Common.Req.addHeader hname value req)
253259 mval
@@ -257,26 +263,26 @@ instance (KnownSymbol sym, ToHttpApiData a, HasClient api)
257263
258264-- | Using a 'HttpVersion' combinator in your API doesn't affect the client
259265-- functions.
260−instance HasClient api
261− => HasClient (HttpVersion :> api) where
266+instance HasClient m api
267+ => HasClient m (HttpVersion :> api) where
262268
263269 type Client m (HttpVersion :> api) =
264270 Client m api
265271
266− clientWithRoute Proxy =
267− clientWithRoute (Proxy :: Proxy api)
272+ clientWithRoute pm Proxy =
273+ clientWithRoute pm (Proxy :: Proxy api)
268274
269275-- | Ignore @'Summary'@ in client functions.
270−instance HasClient api => HasClient (Summary desc :> api) where
276+instance HasClient m api => HasClient m (Summary desc :> api) where
271277 type Client m (Summary desc :> api) = Client m api
272278
273− clientWithRoute _ = clientWithRoute (Proxy :: Proxy api)
279+ clientWithRoute pm _ = clientWithRoute pm (Proxy :: Proxy api)
274280
275281-- | Ignore @'Description'@ in client functions.
276−instance HasClient api => HasClient (Description desc :> api) where
282+instance HasClient m api => HasClient m (Description desc :> api) where
277283 type Client m (Description desc :> api) = Client m api
278284
279− clientWithRoute _ = clientWithRoute (Proxy :: Proxy api)
285+ clientWithRoute pm _ = clientWithRoute pm (Proxy :: Proxy api)
280286
281287-- | If you use a 'QueryParam' in one of your endpoints in your API,
282288-- the corresponding querying function will automatically take
@@ -303,15 +309,15 @@ instance HasClient api => HasClient (Description desc :> api) where
303309-- > -- then you can just use "getBooksBy" to query that endpoint.
304310-- > -- 'getBooksBy Nothing' for all books
305311-- > -- 'getBooksBy (Just "Isaac Asimov")' to get all books by Isaac Asimov
306−instance (KnownSymbol sym, ToHttpApiData a, HasClient api)
307− => HasClient (QueryParam sym a :> api) where
312+instance (KnownSymbol sym, ToHttpApiData a, HasClient m api)
313+ => HasClient m (QueryParam sym a :> api) where
308314
309315 type Client m (QueryParam sym a :> api) =
310316 Maybe a -> Client m api
311317
312318 -- if mparam = Nothing, we don't add it to the query string
313− clientWithRoute Proxy req mparam =
314− clientWithRoute (Proxy :: Proxy api)
319+ clientWithRoute pm Proxy req mparam =
320+ clientWithRoute pm (Proxy :: Proxy api)
315321 (maybe req
316322 (flip (appendToQueryString pname) req . Just)
317323 mparamText
@@ -348,14 +354,14 @@ instance (KnownSymbol sym, ToHttpApiData a, HasClient api)
348354-- > -- 'getBooksBy []' for all books
349355-- > -- 'getBooksBy ["Isaac Asimov", "Robert A. Heinlein"]'
350356-- > -- to get all books by Asimov and Heinlein
351−instance (KnownSymbol sym, ToHttpApiData a, HasClient api)
352− => HasClient (QueryParams sym a :> api) where
357+instance (KnownSymbol sym, ToHttpApiData a, HasClient m api)
358+ => HasClient m (QueryParams sym a :> api) where
353359
354360 type Client m (QueryParams sym a :> api) =
355361 [a] -> Client m api
356362
357− clientWithRoute Proxy req paramlist =
358− clientWithRoute (Proxy :: Proxy api)
363+ clientWithRoute pm Proxy req paramlist =
364+ clientWithRoute pm (Proxy :: Proxy api)
359365 (foldl' (\ req' -> maybe req' (flip (appendToQueryString pname) req' . Just))
360366 req
361367 paramlist'
@@ -386,14 +392,14 @@ instance (KnownSymbol sym, ToHttpApiData a, HasClient api)
386392-- > -- then you can just use "getBooks" to query that endpoint.
387393-- > -- 'getBooksBy False' for all books
388394-- > -- 'getBooksBy True' to only get _already published_ books
389−instance (KnownSymbol sym, HasClient api)
390− => HasClient (QueryFlag sym :> api) where
395+instance (KnownSymbol sym, HasClient m api)
396+ => HasClient m (QueryFlag sym :> api) where
391397
392398 type Client m (QueryFlag sym :> api) =
393399 Bool -> Client m api
394400
395− clientWithRoute Proxy req flag =
396− clientWithRoute (Proxy :: Proxy api)
401+ clientWithRoute pm Proxy req flag =
402+ clientWithRoute pm (Proxy :: Proxy api)
397403 (if flag
398404 then appendToQueryString paramname Nothing req
399405 else req
@@ -404,12 +410,13 @@ instance (KnownSymbol sym, HasClient api)
404410
405411-- | Pick a 'Method' and specify where the server you want to query is. You get
406412-- back the full `Response`.
407−instance HasClient Raw where
413+instance (RunClient m NoContent (Int, ByteString, MediaType, [HTTP.Header], Response ByteString))
414+ => HasClient m Raw where
408415 type Client m Raw
409416 = H.Method -> m (Int, ByteString, MediaType, [HTTP.Header], Response ByteString)
410417
411− clientWithRoute :: Proxy Raw -> Req -> Client Raw
412− clientWithRoute Proxy req httpMethod = do
418+ clientWithRoute :: Proxy m -> Proxy Raw -> Req -> Client m Raw
419+ clientWithRoute pm Proxy req httpMethod = do
413420 runRequest (Proxy :: Proxy NoContent) httpMethod req
414421
415422-- | If you use a 'ReqBody' in one of your endpoints in your API,
@@ -430,14 +437,14 @@ instance HasClient Raw where
430437-- > addBook :: Book -> ClientM Book
431438-- > addBook = client myApi
432439-- > -- then you can just use "addBook" to query that endpoint
433−instance (MimeRender ct a, HasClient api)
434− => HasClient (ReqBody (ct ': cts) a :> api) where
440+instance (MimeRender ct a, HasClient m api)
441+ => HasClient m (ReqBody (ct ': cts) a :> api) where
435442
436443 type Client m (ReqBody (ct ': cts) a :> api) =
437444 a -> Client m api
438445
439− clientWithRoute Proxy req body =
440− clientWithRoute (Proxy :: Proxy api)
446+ clientWithRoute pm Proxy req body =
447+ clientWithRoute pm (Proxy :: Proxy api)
441448 (let ctProxy = Proxy :: Proxy ct
442449 in setReqBodyLBS (mimeRender ctProxy body)
443450 -- We use first contentType from the Accept list
@@ -446,54 +453,54 @@ instance (MimeRender ct a, HasClient api)
446453 )
447454
448455-- | Make the querying function append @path@ to the request path.
449−instance (KnownSymbol path, HasClient api) => HasClient (path :> api) where
456+instance (KnownSymbol path, HasClient m api) => HasClient m (path :> api) where
450457 type Client m (path :> api) = Client m api
451458
452− clientWithRoute Proxy req =
453− clientWithRoute (Proxy :: Proxy api)
459+ clientWithRoute pm Proxy req =
460+ clientWithRoute pm (Proxy :: Proxy api)
454461 (appendToPath p req)
455462
456463 where p = symbolVal (Proxy :: Proxy path)
457464
458−instance HasClient api => HasClient (Vault :> api) where
465+instance HasClient m api => HasClient m (Vault :> api) where
459466 type Client m (Vault :> api) = Client m api
460467
461− clientWithRoute Proxy req =
462− clientWithRoute (Proxy :: Proxy api) req
468+ clientWithRoute pm Proxy req =
469+ clientWithRoute pm (Proxy :: Proxy api) req
463470
464−instance HasClient api => HasClient (RemoteHost :> api) where
471+instance HasClient m api => HasClient m (RemoteHost :> api) where
465472 type Client m (RemoteHost :> api) = Client m api
466473
467− clientWithRoute Proxy req =
468− clientWithRoute (Proxy :: Proxy api) req
474+ clientWithRoute pm Proxy req =
475+ clientWithRoute pm (Proxy :: Proxy api) req
469476
470−instance HasClient api => HasClient (IsSecure :> api) where
477+instance HasClient m api => HasClient m (IsSecure :> api) where
471478 type Client m (IsSecure :> api) = Client m api
472479
473− clientWithRoute Proxy req =
474− clientWithRoute (Proxy :: Proxy api) req
480+ clientWithRoute pm Proxy req =
481+ clientWithRoute pm (Proxy :: Proxy api) req
475482
476−instance HasClient subapi =>
477− HasClient (WithNamedContext name context subapi) where
483+instance HasClient m subapi =>
484+ HasClient m (WithNamedContext name context subapi) where
478485
479486 type Client m (WithNamedContext name context subapi) = Client m subapi
480− clientWithRoute Proxy = clientWithRoute (Proxy :: Proxy subapi)
487+ clientWithRoute pm Proxy = clientWithRoute pm (Proxy :: Proxy subapi)
481488
482−instance ( HasClient api
483− ) => HasClient (AuthProtect tag :> api) where
489+instance ( HasClient m api
490+ ) => HasClient m (AuthProtect tag :> api) where
484491 type Client m (AuthProtect tag :> api)
485492 = AuthenticateReq (AuthProtect tag) -> Client m api
486493
487− clientWithRoute Proxy req (AuthenticateReq (val,func)) =
488− clientWithRoute (Proxy :: Proxy api) (func val req)
494+ clientWithRoute pm Proxy req (AuthenticateReq (val,func)) =
495+ clientWithRoute pm (Proxy :: Proxy api) (func val req)
489496
490497-- * Basic Authentication
491498
492−instance HasClient api => HasClient (BasicAuth realm usr :> api) where
499+instance HasClient m api => HasClient m (BasicAuth realm usr :> api) where
493500 type Client m (BasicAuth realm usr :> api) = BasicAuthData -> Client m api
494501
495− clientWithRoute Proxy req val =
496− clientWithRoute (Proxy :: Proxy api) (basicAuthReq val req)
502+ clientWithRoute pm Proxy req val =
503+ clientWithRoute pm (Proxy :: Proxy api) (basicAuthReq val req)
497504
498505
499506{- Note [Non-Empty Content Types]