git.iko.soy/typeable/servant
on master help sign in
make client endpoint give polymorphic result
0c77a2bGershom
servant-client-core/src/Servant/Client/Core/Internal/HasClient.hs+3−5
@@ -4,7 +4,6 @@
4{-# LANGUAGE FlexibleInstances #-}
4{-# LANGUAGE FlexibleInstances #-}
5{-# LANGUAGE InstanceSigs #-}
5{-# LANGUAGE InstanceSigs #-}
6{-# LANGUAGE MultiParamTypeClasses #-}
6{-# LANGUAGE MultiParamTypeClasses #-}
7−{-# LANGUAGE RankNTypes #-}
8{-# LANGUAGE OverloadedStrings #-}
7{-# LANGUAGE OverloadedStrings #-}
9{-# LANGUAGE PolyKinds #-}
8{-# LANGUAGE PolyKinds #-}
10{-# LANGUAGE ScopedTypeVariables #-}
9{-# LANGUAGE ScopedTypeVariables #-}
@@ -48,6 +47,7 @@ import Servant.API ((:<|>) ((:<|>)), (:>),
48 QueryParams, Raw,
47 QueryParams, Raw,
49 ReflectMethod (..),
48 ReflectMethod (..),
50 RemoteHost, ReqBody,
49 RemoteHost, ReqBody,
50+ ResultStream(..),
51 Stream,
51 Stream,
52 Summary, ToHttpApiData,
52 Summary, ToHttpApiData,
53 Vault, Verb,
53 Vault, Verb,
@@ -253,21 +253,19 @@ instance OVERLAPPING_
253 , getHeadersHList = buildHeadersTo . toList $ responseHeaders response
253 , getHeadersHList = buildHeadersTo . toList $ responseHeaders response
254 }
254 }
255
255
256−data ResultStream a = ResultStream ((forall b. (IO (Maybe (Either String a)) -> IO b) -> IO b))
257−
258instance OVERLAPPABLE_
256instance OVERLAPPABLE_
259 ( RunClient m, MimeUnrender ct a, ReflectMethod method,
257 ( RunClient m, MimeUnrender ct a, ReflectMethod method,
260 FramingUnrender framing a, BuildFromStream a (f a)
258 FramingUnrender framing a, BuildFromStream a (f a)
261 ) => HasClient m (Stream method framing ct (f a)) where
259 ) => HasClient m (Stream method framing ct (f a)) where
262
260
263− type Client m (Stream method framing ct (f a)) = m (ResultStream a)
261+ type Client m (Stream method framing ct (f a)) = m (f a)
264
262
265 clientWithRoute _pm Proxy req = do
263 clientWithRoute _pm Proxy req = do
266 sresp <- streamingRequest req
264 sresp <- streamingRequest req
267 { requestAccept = fromList [contentType (Proxy :: Proxy ct)]
265 { requestAccept = fromList [contentType (Proxy :: Proxy ct)]
268 , requestMethod = reflectMethod (Proxy :: Proxy method)
266 , requestMethod = reflectMethod (Proxy :: Proxy method)
269 }
267 }
270− return $ ResultStream $ \k ->
268+ return . buildFromStream $ ResultStream $ \k ->
271 runStreamingResponse sresp $ \(status,_headers,_httpversion,reader) -> do
269 runStreamingResponse sresp $ \(status,_headers,_httpversion,reader) -> do
272 when (H.statusCode status /= 200) $ error "bad status" --fixme
270 when (H.statusCode status /= 200) $ error "bad status" --fixme
273 let unrender = unrenderFrames (Proxy :: Proxy framing) (Proxy :: Proxy a)
271 let unrender = unrenderFrames (Proxy :: Proxy framing) (Proxy :: Proxy a)
servant/src/Servant/API.hs+2−1
@@ -84,7 +84,8 @@ import Servant.API.QueryParam (QueryFlag, QueryParam,
84 QueryParams)
84 QueryParams)
85import Servant.API.Raw (Raw)
85import Servant.API.Raw (Raw)
86import Servant.API.Stream (Stream, StreamGenerator (..),
86import Servant.API.Stream (Stream, StreamGenerator (..),
87− ToStreamGenerator (..), BuildFromStream (..),
87+ ToStreamGenerator (..),
88+ ResultStream(..), BuildFromStream (..),
88 ByteStringParser (..),
89 ByteStringParser (..),
89 FramingRender (..), BoundaryStrategy (..),
90 FramingRender (..), BoundaryStrategy (..),
90 FramingUnrender (..),
91 FramingUnrender (..),
servant/src/Servant/API/Stream.hs+7−3
@@ -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 TupleSections #-}
10{-# LANGUAGE TupleSections #-}
10{-# OPTIONS_HADDOCK not-home #-}
11{-# OPTIONS_HADDOCK not-home #-}
11
12
@@ -35,11 +36,14 @@ class ToStreamGenerator f a where
35instance ToStreamGenerator StreamGenerator a
36instance ToStreamGenerator StreamGenerator a
36 where toStreamGenerator x = x
37 where toStreamGenerator x = x
37
38
39+-- | Clients reading from streaming endpoints can be implemented as producing a @ResultStream@ that captures the setup, takedown, and incremental logic for a read, being an IO continuation that takes a producer of Just either values or errors that terminates with a Nothing.
40+data ResultStream a = ResultStream ((forall b. (IO (Maybe (Either String a)) -> IO b) -> IO b))
41+
38−-- | BuildFromStream is intended to be implemented for types such as Conduit, Pipe, etc. By implementing this class, all such streaming abstractions can be used directly on the client side for talking to streaming endpoints. The streams we build from are represented as lazy lists of elements interspersed with possible errors.
42+-- | BuildFromStream is intended to be implemented for types such as Conduit, Pipe, etc. By implementing this class, all such streaming abstractions can be used directly on the client side for talking to streaming endpoints.
39class BuildFromStream a b where
43class BuildFromStream a b where
40− buildFromStream :: [Either String a] -> b
44+ buildFromStream :: ResultStream a -> b
41
45
42−instance BuildFromStream a [Either String a]
46+instance BuildFromStream a (ResultStream a)
43 where buildFromStream x = x
47 where buildFromStream x = x
44
48
45-- | The FramingRender class provides the logic for emitting a framing strategy. The strategy emits a header, followed by boundary-delimited data, and finally a termination character. For many strategies, some of these will just be empty bytestrings.
49-- | The FramingRender class provides the logic for emitting a framing strategy. The strategy emits a header, followed by boundary-delimited data, and finally a termination character. For many strategies, some of these will just be empty bytestrings.