1
1
{-# LANGUAGE CPP #-}
2
+ {-# LANGUAGE ApplicativeDo #-}
2
3
{-# OPTIONS_GHC -Wno-missing-methods #-}
3
- {-# LANGUAGE EmptyCase #-}
4
4
module Servant.Client.Core.HasClient (
5
5
clientIn ,
6
6
HasClient (.. ),
@@ -9,17 +9,19 @@ module Servant.Client.Core.HasClient (
9
9
(//) ,
10
10
(/:) ,
11
11
foldMapUnion ,
12
- matchUnion
12
+ matchUnion ,
13
+ fromSomeClientResponse
13
14
) where
14
15
15
16
import Prelude ()
16
17
import Prelude.Compat
17
18
18
19
import Control.Arrow
19
20
(left , (+++) )
21
+ import qualified Data.Text as Text
20
22
import Control.Monad
21
23
(unless )
22
- import qualified Data.ByteString.Lazy as BL
24
+ import qualified Data.ByteString.Lazy as BSL
23
25
import Data.Either
24
26
(partitionEithers )
25
27
import Data.Constraint (Dict (.. ))
@@ -43,13 +45,11 @@ import Data.SOP.Constraint
43
45
import Data.SOP.NP
44
46
(NP (.. ), cpure_NP )
45
47
import Data.SOP.NS
46
- (NS (S ))
48
+ (NS (.. ))
47
49
import Data.String
48
50
(fromString )
49
51
import Data.Text
50
52
(Text , pack )
51
- import Data.Proxy
52
- (Proxy (Proxy ))
53
53
import GHC.TypeLits
54
54
(KnownNat , KnownSymbol , TypeError , symbolVal )
55
55
import Network.HTTP.Types
@@ -71,7 +71,7 @@ import Servant.API.Generic
71
71
(GenericMode (.. ), ToServant , ToServantApi
72
72
, GenericServant , toServant , fromServant )
73
73
import Servant.API.ContentTypes
74
- (contentTypes , AllMime (allMime ), AllMimeUnrender (allMimeUnrender ), AcceptHeader )
74
+ (contentTypes , AllMime (allMime ), AllMimeUnrender (allMimeUnrender ))
75
75
import Servant.API.QueryString (ToDeepQuery (.. ), generateDeepParam )
76
76
import Servant.API.Status
77
77
(statusFromNat )
@@ -87,9 +87,12 @@ import Servant.Client.Core.BasicAuth
87
87
import Servant.Client.Core.ClientError
88
88
import Servant.Client.Core.Request
89
89
import Servant.Client.Core.Response
90
+ import Servant.Client.Core.ResponseUnrender
91
+ import qualified Servant.Client.Core.Response as Response
90
92
import Servant.Client.Core.RunClient
91
- import Servant.API.MultiVerb
93
+ import Servant.API.MultiVerb
92
94
import qualified Network.HTTP.Media as M
95
+ import Data.Typeable
93
96
94
97
-- * Accessing APIs as a Client
95
98
@@ -325,7 +328,7 @@ data ClientParseError = ClientParseError MediaType String | ClientStatusMismatch
325
328
deriving (Eq , Show )
326
329
327
330
class UnrenderResponse (cts :: [Type ]) (a :: Type ) where
328
- unrenderResponse :: Seq. Seq H. Header -> BL . ByteString -> Proxy cts
331
+ unrenderResponse :: Seq. Seq H. Header -> BSL . ByteString -> Proxy cts
329
332
-> [Either (MediaType , String ) a ]
330
333
331
334
instance {-# OVERLAPPABLE #-} AllMimeUnrender cts a => UnrenderResponse cts a where
@@ -367,15 +370,13 @@ instance {-# OVERLAPPING #-}
367
370
368
371
method = reflectMethod $ Proxy @ method
369
372
acceptStatus = statuses (Proxy @ as )
370
- response <- runRequestAcceptStatus (Just acceptStatus) request {requestMethod = method, requestAccept = accept}
373
+ response@ Response {responseBody= body, responseStatusCode= status, responseHeaders= headers}
374
+ <- runRequestAcceptStatus (Just acceptStatus) (request {requestMethod = method, requestAccept = accept})
371
375
responseContentType <- checkContentTypeHeader response
372
376
unless (any (matches responseContentType) accept) $ do
373
377
throwClientError $ UnsupportedContentType responseContentType response
374
378
375
- let status = responseStatusCode response
376
- body = responseBody response
377
- headers = responseHeaders response
378
- res = tryParsers status $ mimeUnrenders (Proxy @ contentTypes ) headers body
379
+ let res = tryParsers status $ mimeUnrenders (Proxy @ contentTypes ) headers body
379
380
case res of
380
381
Left errors -> throwClientError $ DecodeFailure (T. pack (show errors)) response
381
382
Right x -> return x
@@ -399,7 +400,7 @@ instance {-# OVERLAPPING #-}
399
400
All (UnrenderResponse cts ) xs =>
400
401
Proxy cts ->
401
402
Seq. Seq H. Header ->
402
- BL . ByteString ->
403
+ BSL . ByteString ->
403
404
NP ([] :.: Either (MediaType , String )) xs
404
405
mimeUnrenders ctp headers body = cpure_NP
405
406
(Proxy @ (UnrenderResponse cts ))
@@ -416,10 +417,10 @@ instance {-# OVERLAPPABLE #-}
416
417
417
418
hoistClientMonad _ _ f ma = f ma
418
419
419
- clientWithRoute _pm Proxy req = withStreamingRequest req' $ \ gres -> do
420
- let mimeUnrender' = mimeUnrender (Proxy :: Proxy ct ) :: BL . ByteString -> Either String chunk
420
+ clientWithRoute _pm Proxy req = withStreamingRequest req' $ \ Response {responseBody = body} -> do
421
+ let mimeUnrender' = mimeUnrender (Proxy :: Proxy ct ) :: BSL . ByteString -> Either String chunk
421
422
framingUnrender' = framingUnrender (Proxy :: Proxy framing ) mimeUnrender'
422
- fromSourceIO $ framingUnrender' $ responseBody gres
423
+ fromSourceIO $ framingUnrender' body
423
424
where
424
425
req' = req
425
426
{ requestAccept = fromList [contentType (Proxy :: Proxy ct )]
@@ -436,13 +437,14 @@ instance {-# OVERLAPPING #-}
436
437
437
438
hoistClientMonad _ _ f ma = f ma
438
439
439
- clientWithRoute _pm Proxy req = withStreamingRequest req' $ \ gres -> do
440
- let mimeUnrender' = mimeUnrender (Proxy :: Proxy ct ) :: BL. ByteString -> Either String chunk
440
+ clientWithRoute _pm Proxy req = withStreamingRequest req' $
441
+ \ Response {responseBody= body, responseHeaders= headers} -> do
442
+ let mimeUnrender' = mimeUnrender (Proxy :: Proxy ct ) :: BSL. ByteString -> Either String chunk
441
443
framingUnrender' = framingUnrender (Proxy :: Proxy framing ) mimeUnrender'
442
- val <- fromSourceIO $ framingUnrender' $ responseBody gres
444
+ val <- fromSourceIO $ framingUnrender' body
443
445
return $ Headers
444
446
{ getResponse = val
445
- , getHeadersHList = buildHeadersTo . toList $ responseHeaders gres
447
+ , getHeadersHList = buildHeadersTo $ toList headers
446
448
}
447
449
448
450
where
@@ -760,7 +762,7 @@ instance
760
762
761
763
sourceIO = framingRender
762
764
framingP
763
- (mimeRender ctypeP :: chunk -> BL . ByteString )
765
+ (mimeRender ctypeP :: chunk -> BSL . ByteString )
764
766
(toSourceIO body)
765
767
766
768
-- | Make the querying function append @path@ to the request path.
@@ -975,19 +977,9 @@ x // f = f x
975
977
(/:) :: (a -> b -> c ) -> b -> a -> c
976
978
(/:) = flip
977
979
978
- class IsResponseList cs as where
979
- responseListRender :: AcceptHeader -> Union (ResponseTypes as ) -> Maybe InternalResponse
980
- responseListUnrender :: M. MediaType -> InternalResponse -> UnrenderResult (Union (ResponseTypes as ))
981
-
982
- responseListStatuses :: [Status ]
983
-
984
- instance IsResponseList cs '[] where
985
- responseListRender _ x = case x of {}
986
- responseListUnrender _ _ = empty
987
- responseListStatuses = []
988
980
989
981
instance
990
- ( IsResponseList cs as ,
982
+ ( ResponseListUnrender cs as ,
991
983
AllMime cs ,
992
984
ReflectMethod method ,
993
985
AsUnion as r ,
@@ -998,7 +990,7 @@ instance
998
990
type Client m (MultiVerb method cs as r ) = m r
999
991
1000
992
clientWithRoute _ _ req = do
1001
- response <-
993
+ response@ Response {responseBody = body} <-
1002
994
runRequestAcceptStatus
1003
995
(Just (responseListStatuses @ cs @ as ))
1004
996
req
@@ -1012,9 +1004,9 @@ instance
1012
1004
1013
1005
-- FUTUREWORK: support streaming
1014
1006
let sresp =
1015
- if LBS .null (responseBody response)
1016
- then SomeResponse response {responseBody = () }
1017
- else SomeResponse response
1007
+ if BSL .null body
1008
+ then SomeClientResponse $ response {Response. responseBody = () }
1009
+ else SomeClientResponse response
1018
1010
case responseListUnrender @ cs @ as c sresp of
1019
1011
StatusMismatch -> throwClientError (DecodeFailure " Status mismatch" response)
1020
1012
UnrenderError e -> throwClientError (DecodeFailure (Text. pack e) response)
@@ -1064,11 +1056,11 @@ checkContentTypeHeader response =
1064
1056
1065
1057
decodedAs :: forall ct a m . (MimeUnrender ct a , RunClient m )
1066
1058
=> Response -> Proxy ct -> m a
1067
- decodedAs response ct = do
1059
+ decodedAs response@ Response {responseBody = body} ct = do
1068
1060
responseContentType <- checkContentTypeHeader response
1069
1061
unless (any (matches responseContentType) accept) $
1070
1062
throwClientError $ UnsupportedContentType responseContentType response
1071
- case mimeUnrender ct $ responseBody response of
1063
+ case mimeUnrender ct body of
1072
1064
Left err -> throwClientError $ DecodeFailure (T. pack err) response
1073
1065
Right val -> return val
1074
1066
where
0 commit comments