git.iko.soy/typeable/servant-reflex
on master help sign in
Add Multi interface for making batch requests
5867eaeGreg Hale
exec/Example.hs+32−5
@@ -6,25 +6,51 @@
6
6
7module Main where
7module Main where
8
8
9+------------------------------------------------------------------------------
9import Data.Bool
10import Data.Bool
10import Data.Maybe
11import Data.Maybe
11import Control.Monad.Fix (MonadFix)
12import Control.Monad.Fix (MonadFix)
12−import Data.Monoid ((<>))
13+import Data.Monoid (First(..), (<>))
13import Data.Text (Text)
14import Data.Text (Text)
14import qualified Data.Text as T
15import qualified Data.Text as T
15import Servant.API
16import Servant.API
16−import Servant.Reflex
17import API
17import API
18import Data.Proxy
18import Data.Proxy
19import Text.Read (readMaybe)
19import Text.Read (readMaybe)
20import Reflex.Dom
20import Reflex.Dom
21+------------------------------------------------------------------------------
22+import Servant.Reflex
23+import Servant.Reflex.Multi
24+
21
25
22api :: Proxy API
26api :: Proxy API
23api = Proxy
27api = Proxy
24
28
25main :: IO ()
29main :: IO ()
26−main = mainWidget run
30+main = mainWidget $ do
27−
31+ divClass "example-base" run
32+ divClass "example-multi" runMulti
33+
34+
35+runMulti :: forall t m. (SupportsServantReflex t m,
36+ DomBuilder t m,
37+ DomBuilderSpace m ~ GhcjsDomSpace,
38+ MonadFix m,
39+ PostBuild t m,
40+ MonadHold t m) => m ()
41+runMulti = do
42+ url <- baseUrlWidget
43+ el "br" blank
44+ let (_ :<|> _ :<|> _ :<|> dbl :<|> _ :<|> _ ) =
45+ clientA api (Proxy :: Proxy m) (Proxy :: Proxy []) url
46+ num :: Dynamic t (Either Text Double) <- fmap (note "No read" . readMaybe . T.unpack) . value <$> textInput def
47+ num2 :: Dynamic t (Either Text Double) <- fmap (note "No read" . readMaybe . T.unpack) . value <$> textInput def
48+ -- dynText =<< holdDyn "waiting" (T.pack . show <$> num)
49+ -- numLabeled :: Event t (First Int, Double) <- zipListWithEvent (,) (First . Just <$> [0..]) num
50+ b <- button "Run dbl multi"
51+ r <- dbl [num,num2] b
52+ dynText =<< holdDyn "Waiting" (T.pack . show . fmapMaybe reqSuccess <$> r)
53+ return ()
28
54
29run :: forall t m. (SupportsServantReflex t m,
55run :: forall t m. (SupportsServantReflex t m,
30 DomBuilder t m,
56 DomBuilder t m,
@@ -39,6 +65,7 @@ run = do
39 url <- baseUrlWidget
65 url <- baseUrlWidget
40 el "br" (return ())
66 el "br" (return ())
41 dynText $ showBaseUrl <$> url
67 dynText $ showBaseUrl <$> url
68+
42 el "br" (return ())
69 el "br" (return ())
43
70
44 -- Name the computed API client functions
71 -- Name the computed API client functions
@@ -90,7 +117,7 @@ run = do
90 text "A Double to double"
117 text "A Double to double"
91 el "br" $ return ()
118 el "br" $ return ()
92 dblinp <- fmap value $ divClass "double-input" $ textInput def
119 dblinp <- fmap value $ divClass "double-input" $ textInput def
93− dblBtn <- divClass "double-button" $ button "Double it"
120+ (dblBtn) <- divClass "double-button" $ button "Double it"
94 dblResp <- dbl (fmap (note "read failure" . readMaybe . T.unpack) $
121 dblResp <- dbl (fmap (note "read failure" . readMaybe . T.unpack) $
95 dblinp) dblBtn
122 dblinp) dblBtn
96 divClass "double-errors" $ dynText =<<
123 divClass "double-errors" $ dynText =<<
servant-reflex.cabal+2−1
@@ -1,5 +1,5 @@
1Name: servant-reflex
1Name: servant-reflex
2−Version: 0.2
2+Version: 0.2.1
3Synopsis: Servant reflex API generator
3Synopsis: Servant reflex API generator
4Description: Servant reflex API generator
4Description: Servant reflex API generator
5License: AllRightsReserved
5License: AllRightsReserved
@@ -14,6 +14,7 @@ Cabal-version: >=1.10
14library
14library
15 exposed-modules:
15 exposed-modules:
16 Servant.Reflex
16 Servant.Reflex
17+ Servant.Reflex.Multi
17
18
18 other-modules:
19 other-modules:
19 Servant.Common.BaseUrl
20 Servant.Common.BaseUrl
src/Servant/Common/Req.hs+119−16
@@ -1,3 +1,4 @@
1+{-# LANGUAGE AllowAmbiguousTypes #-}
1{-# LANGUAGE DeriveDataTypeable #-}
2{-# LANGUAGE DeriveDataTypeable #-}
2{-# LANGUAGE CPP #-}
3{-# LANGUAGE CPP #-}
3{-# LANGUAGE FlexibleContexts #-}
4{-# LANGUAGE FlexibleContexts #-}
@@ -6,10 +7,14 @@
6{-# LANGUAGE LambdaCase #-}
7{-# LANGUAGE LambdaCase #-}
7{-# LANGUAGE ScopedTypeVariables #-}
8{-# LANGUAGE ScopedTypeVariables #-}
8{-# LANGUAGE TupleSections #-}
9{-# LANGUAGE TupleSections #-}
10+
11+{-# LANGUAGE EmptyCase #-}
9module Servant.Common.Req where
12module Servant.Common.Req where
10
13
11-------------------------------------------------------------------------------
14-------------------------------------------------------------------------------
15+import Control.Concurrent
12import Control.Applicative (liftA2, liftA3)
16import Control.Applicative (liftA2, liftA3)
17+import Control.Monad.IO.Class (MonadIO, liftIO)
13import qualified Data.ByteString.Lazy.Char8 as BL
18import qualified Data.ByteString.Lazy.Char8 as BL
14import qualified Data.Map as Map
19import qualified Data.Map as Map
15import Data.Maybe (catMaybes)
20import Data.Maybe (catMaybes)
@@ -18,6 +23,7 @@ import Data.Proxy (Proxy(..))
18import Data.Text (Text)
23import Data.Text (Text)
19import qualified Data.Text as T
24import qualified Data.Text as T
20import qualified Data.Text.Encoding as TE
25import qualified Data.Text.Encoding as TE
26+import Data.Traversable
21import Reflex.Dom
27import Reflex.Dom
22import Servant.Common.BaseUrl (BaseUrl, showBaseUrl, SupportsServantReflex)
28import Servant.Common.BaseUrl (BaseUrl, showBaseUrl, SupportsServantReflex)
23import Servant.API.ContentTypes (MimeUnrender(..), NoContent(..))
29import Servant.API.ContentTypes (MimeUnrender(..), NoContent(..))
@@ -96,20 +102,13 @@ addHeader :: (ToHttpApiData a, Reflex t) => Text -> Dynamic t (Either Text a) ->
96addHeader name val req = req { headers = (name, (fmap . fmap) (TE.decodeUtf8 . toHeader) val) : headers req }
102addHeader name val req = req { headers = (name, (fmap . fmap) (TE.decodeUtf8 . toHeader) val) : headers req }
97
103
98
104
99−-- * performing requests
105+reqToReflexRequest
100−
106+ :: forall t. Reflex t
101−displayHttpRequest :: Text -> Text
102−displayHttpRequest httpmethod = "HTTP " <> httpmethod <> " request"
103−
104−-- | This function actually performs the request.
105−performRequest :: forall t m.(SupportsServantReflex t m)
106− => Text
107+ => Text
107− -> Req t
108+ -> Req t
108− -> Dynamic t BaseUrl
109+ -> Dynamic t BaseUrl
109− -> Event t ()
110+ -> (Dynamic t (Either Text (XhrRequest XhrPayload)))
110− -> m (Event t XhrResponse, Event t Text)
111−performRequest reqMeth req reqHost trigger = do
111+reqToReflexRequest reqMeth req reqHost =
112−
113 let t :: Dynamic t [Either Text Text]
112 let t :: Dynamic t [Either Text Text]
114 t = sequence $ reverse $ reqPathParts req
113 t = sequence $ reverse $ reqPathParts req
115
114
@@ -142,8 +141,8 @@ performRequest reqMeth req reqHost trigger = do
142 queryPartStrings' = fmap (sequence . catMaybes) $ sequence queryPartStrings :: Dynamic t (Either Text [Text])
141 queryPartStrings' = fmap (sequence . catMaybes) $ sequence queryPartStrings :: Dynamic t (Either Text [Text])
143 queryString :: Dynamic t (Either Text Text) =
142 queryString :: Dynamic t (Either Text Text) =
144 ffor queryPartStrings' $ \qs -> fmap (T.intercalate "&") qs
143 ffor queryPartStrings' $ \qs -> fmap (T.intercalate "&") qs
145−-- ffor queryPartStrings' $ \qs -> fmap (T.intercalate "&") (sequence qs)
146− xhrUrl = (liftA3 . liftA3) (\a p q -> a </> if T.null q then p else p <> "?" <> q) baseUrl urlPath queryString
144+ xhrUrl = (liftA3 . liftA3) (\a p q -> a </> if T.null q then p else p <> "?" <> q)
145+ baseUrl urlPath queryString
147 where
146 where
148 (</>) :: Text -> Text -> Text
147 (</>) :: Text -> Text -> Text
149 x </> y | ("/" `T.isSuffixOf` x) || ("/" `T.isPrefixOf` y) = x <> y
148 x </> y | ("/" `T.isSuffixOf` x) || ("/" `T.isPrefixOf` y) = x <> y
@@ -202,6 +201,71 @@ performRequest reqMeth req reqHost trigger = do
202
201
203 xhrReq = (liftA2 . liftA2) (\p opt -> XhrRequest reqMeth p opt) xhrUrl (addAuth xhrOpts)
202 xhrReq = (liftA2 . liftA2) (\p opt -> XhrRequest reqMeth p opt) xhrUrl (addAuth xhrOpts)
204
203
204+ in xhrReq
205+
206+-- * performing requests
207+
208+displayHttpRequest :: Text -> Text
209+displayHttpRequest httpmethod = "HTTP " <> httpmethod <> " request"
210+
211+-- | This function actually performs the request.
212+performRequests :: forall t m f.(SupportsServantReflex t m, Traversable f)
213+ => Text
214+ -> f (Req t)
215+ -> Dynamic t BaseUrl
216+ -> Event t ()
217+ -> m (Event t (f (Either Text XhrResponse)))
218+performRequests reqMeth rs reqHost trigger = do
219+ let xhrReqs = sequence $ (\r -> reqToReflexRequest reqMeth r reqHost) <$> rs :: Dynamic t (f (Either Text (XhrRequest XhrPayload)))
220+ let reqs = tagPromptlyDyn xhrReqs trigger
221+ resps <- performSomeRequestsAsync reqs
222+ return resps
223+
224+-- | Issues a collection of requests when the supplied Event fires. When ALL requests from a given firing complete, the results are collected and returned via the return Event.
225+performSomeRequestsAsync
226+ :: (MonadIO (Performable m),
227+ HasWebView (Performable m),
228+ PerformEvent t m,
229+ TriggerEvent t m,
230+ Traversable f,
231+ IsXhrPayload a)
232+ => Event t (f (Either Text (XhrRequest a)))
233+ -> m (Event t (f (Either Text XhrResponse)))
234+performSomeRequestsAsync = performSomeRequestsAsync' newXMLHttpRequest . fmap return
235+
236+
237+------------------------------------------------------------------------------
238+-- | A modified version or Reflex.Dom.Xhr.performRequestsAsync
239+-- that accepts 'f (Either e (XhrRequestb))' events
240+performSomeRequestsAsync'
241+ :: (MonadIO (Performable m), PerformEvent t m, TriggerEvent t m, Traversable f)
242+ => (XhrRequest b -> (a -> IO ()) -> Performable m XMLHttpRequest)
243+ -> Event t (Performable m (f (Either Text (XhrRequest b)))) -> m (Event t (f (Either Text a)))
244+performSomeRequestsAsync' newXhr req = performEventAsync $ ffor req $ \hrs cb -> do
245+ rs <- hrs
246+ resps <- forM rs $ \r -> case r of
247+ Left e -> do
248+ resp <- liftIO $ newMVar (Left e)
249+ return resp
250+ Right r' -> do
251+ resp <- liftIO newEmptyMVar
252+ _ <- newXhr r' $ liftIO . putMVar resp . Right
253+ return resp
254+ _ <- liftIO $ forkIO $ cb =<< forM resps takeMVar
255+ return ()
256+
257+
258+
259+-- | This function actually performs the request.
260+performRequest :: forall t m .(SupportsServantReflex t m)
261+ => Text
262+ -> (Req t)
263+ -> Dynamic t BaseUrl
264+ -> Event t ()
265+ -> m (Event t (XhrResponse), Event t Text)
266+performRequest reqMeth req reqHost trigger = do
267+
268+ let xhrReq = reqToReflexRequest reqMeth req reqHost
205 let reqs = tagPromptlyDyn xhrReq trigger
269 let reqs = tagPromptlyDyn xhrReq trigger
206 okReqs = fmapMaybe (either (const Nothing) Just) reqs
270 okReqs = fmapMaybe (either (const Nothing) Just) reqs
207 badReqs = fmapMaybe (either Just (const Nothing)) reqs
271 badReqs = fmapMaybe (either Just (const Nothing)) reqs
@@ -210,6 +274,7 @@ performRequest reqMeth req reqHost trigger = do
210
274
211 return (resps, badReqs)
275 return (resps, badReqs)
212
276
277+
213#ifdef ghcjs_HOST_OS
278#ifdef ghcjs_HOST_OS
214type XhrPayload = String
279type XhrPayload = String
215bytesToPayload :: BL.ByteString -> XhrPayload
280bytesToPayload :: BL.ByteString -> XhrPayload
@@ -229,6 +294,20 @@ performRequestNoBody reqMeth req reqHost trigger = do
229 (resp, badReq) <- performRequest reqMeth req reqHost trigger
294 (resp, badReq) <- performRequest reqMeth req reqHost trigger
230 return $ leftmost [ fmap (ResponseSuccess NoContent) resp, fmap RequestFailure badReq]
295 return $ leftmost [ fmap (ResponseSuccess NoContent) resp, fmap RequestFailure badReq]
231
296
297+performRequestsNoBody :: forall t m f .(SupportsServantReflex t m, Traversable f)
298+ => Text
299+ -> f (Req t)
300+ -> Dynamic t BaseUrl
301+ -> Event t () -> m (Event t (f (ReqResult NoContent)))
302+performRequestsNoBody reqMeth reqs reqHost trigger = do
303+ resp <- performRequests reqMeth reqs reqHost trigger
304+ return $ (fmap . fmap) aux resp
305+ where
306+ aux (Right x) = ResponseSuccess NoContent x
307+ aux (Left e) = RequestFailure e
308+ -- return $ leftmost [ fmap (ResponseSuccess NoContent) resp, fmap RequestFailure badReq]
309+
310+
232
311
233performRequestCT :: (SupportsServantReflex t m,
312performRequestCT :: (SupportsServantReflex t m,
234 MimeUnrender ct a)
313 MimeUnrender ct a)
@@ -244,5 +323,29 @@ performRequestCT ct reqMeth req reqHost trigger = do
244 (Left e, r) -> ResponseFailure (T.pack e) r
323 (Left e, r) -> ResponseFailure (T.pack e) r
245 return $ leftmost [reqs, fmap RequestFailure badReq]
324 return $ leftmost [reqs, fmap RequestFailure badReq]
246
325
326+performRequestsCT
327+ :: (SupportsServantReflex t m,
328+ MimeUnrender ct a, Traversable f)
329+ => Proxy ct
330+ -> Text
331+ -> f (Req t)
332+ -> Dynamic t BaseUrl
333+ -> Event t ()
334+ -> m (Event t (f (ReqResult a)))
335+performRequestsCT ct reqMeth reqs reqHost trigger = do
336+ resps <- performRequests reqMeth reqs reqHost trigger
337+ return $ ffor resps $ \eithXhrs -> ffor eithXhrs $ \eithXhr -> case eithXhr of
338+ Left e -> RequestFailure e
339+ Right x -> case _xhrResponse_responseText x of
340+ Nothing -> ResponseFailure "No body text" x
341+ Just bod -> case mimeUnrender ct . BL.fromStrict . TE.encodeUtf8 $ bod of
342+ Left e -> ResponseFailure (T.pack e) x
343+ Right a -> ResponseSuccess a x
344+
345+
247note :: e -> Maybe a -> Either e a
346note :: e -> Maybe a -> Either e a
248note e = maybe (Left e) Right
347note e = maybe (Left e) Right
348+
349+fmapL :: (e -> e') -> Either e a -> Either e' a
350+fmapL _ (Right a) = Right a
351+fmapL f (Left e) = Left (f e)
src/Servant/Reflex.hs+42−8
@@ -1,3 +1,4 @@
1+{-# LANGUAGE AllowAmbiguousTypes #-}
1{-# LANGUAGE CPP #-}
2{-# LANGUAGE CPP #-}
2{-# LANGUAGE DataKinds #-}
3{-# LANGUAGE DataKinds #-}
3{-# LANGUAGE FlexibleContexts #-}
4{-# LANGUAGE FlexibleContexts #-}
@@ -18,12 +19,14 @@
18-- API.
19-- API.
19module Servant.Reflex
20module Servant.Reflex
20 ( client
21 ( client
22+ , BuildHeaderKeysTo(..)
23+ , toHeaders
21 , HasClient(..)
24 , HasClient(..)
22 , module Servant.Common.Req
25 , module Servant.Common.Req
23 , module Servant.Common.BaseUrl
26 , module Servant.Common.BaseUrl
24 ) where
27 ) where
25
28
26−-------------------------------------------------------------------------------
29+------------------------------------------------------------------------------
27import Control.Applicative
30import Control.Applicative
28import Data.Monoid ((<>))
31import Data.Monoid ((<>))
29import qualified Data.Set as Set
32import qualified Data.Set as Set
@@ -43,6 +46,14 @@ import Servant.API ((:<|>)(..),(:>), BasicAuth,
43 QueryParams, Raw, ReflectMethod(..),
46 QueryParams, Raw, ReflectMethod(..),
44 RemoteHost, ReqBody,
47 RemoteHost, ReqBody,
45 ToHttpApiData(..), Vault, Verb)
48 ToHttpApiData(..), Vault, Verb)
49+
50+import Reflex.Dom (Dynamic, Event, Reflex,
51+ XhrRequest(..),
52+ XhrResponseHeaders(..),
53+ XhrResponse(..), ffor, fmapMaybe,
54+ leftmost, performRequestAsync,
55+ tagPromptlyDyn )
56+------------------------------------------------------------------------------
46import Servant.Common.BaseUrl (BaseUrl(..), Scheme(..), baseUrlWidget,
57import Servant.Common.BaseUrl (BaseUrl(..), Scheme(..), baseUrlWidget,
47 showBaseUrl,
58 showBaseUrl,
48 SupportsServantReflex)
59 SupportsServantReflex)
@@ -50,17 +61,14 @@ import Servant.Common.Req (Req, ReqResult(..), QParam(..),
50 QueryPart(..), addHeader, authData,
61 QueryPart(..), addHeader, authData,
51 defReq, prependToPathParts,
62 defReq, prependToPathParts,
52 performRequestCT,
63 performRequestCT,
64+ performRequestsCT,
53 performRequestNoBody,
65 performRequestNoBody,
66+ performRequestsNoBody,
67+ performSomeRequestsAsync,
54 qParamToQueryPart, reqBody,
68 qParamToQueryPart, reqBody,
55 reqSuccess, reqFailure,
69 reqSuccess, reqFailure,
56 reqMethod, respHeaders, response,
70 reqMethod, respHeaders, response,
57 qParams)
71 qParams)
58−import Reflex.Dom (Dynamic, Event, Reflex,
59− XhrRequest(..),
60− XhrResponseHeaders(..),
61− XhrResponse(..), ffor, fmapMaybe,
62− leftmost, performRequestAsync,
63− tagPromptlyDyn )
64
72
65-- * Accessing APIs as a Client
73-- * Accessing APIs as a Client
66
74
@@ -81,6 +89,7 @@ client :: (HasClient t m layout)
81 => Proxy layout -> Proxy m -> Dynamic t BaseUrl -> Client t m layout
89 => Proxy layout -> Proxy m -> Dynamic t BaseUrl -> Client t m layout
82client p q baseurl = clientWithRoute p q defReq baseurl
90client p q baseurl = clientWithRoute p q defReq baseurl
83
91
92+
84-- | This class lets us define how each API combinator
93-- | This class lets us define how each API combinator
85-- influences the creation of an HTTP request. It's mostly
94-- influences the creation of an HTTP request. It's mostly
86-- an internal class, you can just use 'client'.
95-- an internal class, you can just use 'client'.
@@ -91,10 +100,12 @@ class HasClient t m layout where
91
100
92instance (HasClient t m a, HasClient t m b) => HasClient t m (a :<|> b) where
101instance (HasClient t m a, HasClient t m b) => HasClient t m (a :<|> b) where
93 type Client t m (a :<|> b) = Client t m a :<|> Client t m b
102 type Client t m (a :<|> b) = Client t m a :<|> Client t m b
103+
94 clientWithRoute Proxy q req baseurl =
104 clientWithRoute Proxy q req baseurl =
95 clientWithRoute (Proxy :: Proxy a) q req baseurl :<|>
105 clientWithRoute (Proxy :: Proxy a) q req baseurl :<|>
96 clientWithRoute (Proxy :: Proxy b) q req baseurl
106 clientWithRoute (Proxy :: Proxy b) q req baseurl
97
107
108+
98-- Capture. Example:
109-- Capture. Example:
99-- > type MyApi = "books" :> Capture "isbn" Text :> Get '[JSON] Book
110-- > type MyApi = "books" :> Capture "isbn" Text :> Get '[JSON] Book
100-- >
111-- >
@@ -106,6 +117,7 @@ instance (HasClient t m a, HasClient t m b) => HasClient t m (a :<|> b) where
106-- -> Event t ()
117-- -> Event t ()
107-- -> m (Event t (Either XhrError (Text, Book)))
118-- -> m (Event t (Either XhrError (Text, Book)))
108-- > getBook = client myApi (constDyn host)
119-- > getBook = client myApi (constDyn host)
120+
109instance (SupportsServantReflex t m, ToHttpApiData a, HasClient t m sublayout)
121instance (SupportsServantReflex t m, ToHttpApiData a, HasClient t m sublayout)
110 => HasClient t m (Capture capture a :> sublayout) where
122 => HasClient t m (Capture capture a :> sublayout) where
111
123
@@ -117,9 +129,9 @@ instance (SupportsServantReflex t m, ToHttpApiData a, HasClient t m sublayout)
117 q
129 q
118 (prependToPathParts p req)
130 (prependToPathParts p req)
119 baseurl
131 baseurl
120−
121 where p = (fmap . fmap) (toUrlPiece) val
132 where p = (fmap . fmap) (toUrlPiece) val
122
133
134+
123-- VERB (Returning content) --
135-- VERB (Returning content) --
124instance {-# OVERLAPPABLE #-}
136instance {-# OVERLAPPABLE #-}
125 -- Note [Non-Empty Content Types]
137 -- Note [Non-Empty Content Types]
@@ -134,6 +146,9 @@ instance {-# OVERLAPPABLE #-}
134 where method = E.decodeUtf8 $ reflectMethod (Proxy :: Proxy method)
146 where method = E.decodeUtf8 $ reflectMethod (Proxy :: Proxy method)
135 req' = req { reqMethod = method }
147 req' = req { reqMethod = method }
136
148
149+
150+
151+
137-- -- VERB (No content) --
152-- -- VERB (No content) --
138instance {-# OVERLAPPING #-}
153instance {-# OVERLAPPING #-}
139 (ReflectMethod method, SupportsServantReflex t m) =>
154 (ReflectMethod method, SupportsServantReflex t m) =>
@@ -146,6 +161,7 @@ instance {-# OVERLAPPING #-}
146 performRequestNoBody method req baseurl
161 performRequestNoBody method req baseurl
147 where method = E.decodeUtf8 $ reflectMethod (Proxy :: Proxy method)
162 where method = E.decodeUtf8 $ reflectMethod (Proxy :: Proxy method)
148
163
164+
149toHeaders :: BuildHeadersTo ls => ReqResult a -> ReqResult (Headers ls a)
165toHeaders :: BuildHeadersTo ls => ReqResult a -> ReqResult (Headers ls a)
150toHeaders r =
166toHeaders r =
151 let toBS = E.encodeUtf8
167 let toBS = E.encodeUtf8
@@ -186,6 +202,7 @@ instance {-# OVERLAPPABLE #-}
186 OnlyHeaders (Set.fromList (buildHeaderKeysTo (Proxy :: Proxy ls)))
202 OnlyHeaders (Set.fromList (buildHeaderKeysTo (Proxy :: Proxy ls)))
187 }
203 }
188
204
205+
189-- HEADERS Verb (No content) --
206-- HEADERS Verb (No content) --
190instance {-# OVERLAPPABLE #-}
207instance {-# OVERLAPPABLE #-}
191 ( BuildHeadersTo ls, BuildHeaderKeysTo ls, ReflectMethod method,
208 ( BuildHeadersTo ls, BuildHeaderKeysTo ls, ReflectMethod method,
@@ -202,6 +219,7 @@ instance {-# OVERLAPPABLE #-}
202 }
219 }
203
220
204
221
222+
205-- HEADER
223-- HEADER
206-- > newtype Referer = Referer { referrer :: Text }
224-- > newtype Referer = Referer { referrer :: Text }
207-- > deriving (Eq, Show, Generic, FromText, ToHttpApiData)
225-- > deriving (Eq, Show, Generic, FromText, ToHttpApiData)
@@ -229,6 +247,9 @@ instance (KnownSymbol sym, ToHttpApiData a,
229 baseurl
247 baseurl
230 where hname = T.pack $ symbolVal (Proxy :: Proxy sym)
248 where hname = T.pack $ symbolVal (Proxy :: Proxy sym)
231
249
250+
251+
252+
232-- | Using a 'HttpVersion' combinator in your API doesn't affect the client
253-- | Using a 'HttpVersion' combinator in your API doesn't affect the client
233-- functions.
254-- functions.
234instance HasClient t m sublayout
255instance HasClient t m sublayout
@@ -241,6 +262,7 @@ instance HasClient t m sublayout
241 clientWithRoute (Proxy :: Proxy sublayout) q
262 clientWithRoute (Proxy :: Proxy sublayout) q
242
263
243
264
265+
244-- | If you use a 'QueryParam' in one of your endpoints in your API,
266-- | If you use a 'QueryParam' in one of your endpoints in your API,
245-- the corresponding querying function will automatically take
267-- the corresponding querying function will automatically take
246-- an additional argument of the type specified by your 'QueryParam',
268-- an additional argument of the type specified by your 'QueryParam',
@@ -284,6 +306,8 @@ instance (KnownSymbol sym, ToHttpApiData a, HasClient t m sublayout, Reflex t)
284 p prm = QueryPartParam $ fmap qParamToQueryPart prm -- (fmap . fmap) (unpack . toQueryParam) prm
306 p prm = QueryPartParam $ fmap qParamToQueryPart prm -- (fmap . fmap) (unpack . toQueryParam) prm
285 paramPair = (T.pack pname, p mparam)
307 paramPair = (T.pack pname, p mparam)
286
308
309+
310+
287-- | If you use a 'QueryParams' in one of your endpoints in your API,
311-- | If you use a 'QueryParams' in one of your endpoints in your API,
288-- the corresponding querying function will automatically take
312-- the corresponding querying function will automatically take
289-- an additional argument, a list of values of the type specified
313-- an additional argument, a list of values of the type specified
@@ -327,6 +351,7 @@ instance (KnownSymbol sym, ToHttpApiData a, HasClient t m sublayout, Reflex t)
327 paramlist
351 paramlist
328
352
329
353
354+
330-- | If you use a 'QueryFlag' in one of your endpoints in your API,
355-- | If you use a 'QueryFlag' in one of your endpoints in your API,
331-- the corresponding querying function will automatically take
356-- the corresponding querying function will automatically take
332-- an additional 'Bool' argument.
357-- an additional 'Bool' argument.
@@ -365,6 +390,7 @@ instance (KnownSymbol sym, HasClient t m sublayout, Reflex t)
365 pName = symbolVal (Proxy :: Proxy sym)
390 pName = symbolVal (Proxy :: Proxy sym)
366
391
367
392
393+
368-- | Pick a 'Method' and specify where the server you want to query is. You get
394-- | Pick a 'Method' and specify where the server you want to query is. You get
369-- back the full `Response`.
395-- back the full `Response`.
370-- TODO redo
396-- TODO redo
@@ -389,6 +415,7 @@ instance SupportsServantReflex t m => HasClient t m Raw where
389 ,fmap RequestFailure badReq]
415 ,fmap RequestFailure badReq]
390
416
391
417
418+
392hush :: Either e a -> Maybe a
419hush :: Either e a -> Maybe a
393hush = either (const Nothing) Just
420hush = either (const Nothing) Just
394
421
@@ -430,6 +457,8 @@ instance (MimeRender ct a, HasClient t m sublayout, Reflex t)
430 (\b -> (mimeRender ctProxy b, ctString))
457 (\b -> (mimeRender ctProxy b, ctString))
431 body
458 body
432
459
460+
461+
433-- | Make the querying function append @path@ to the request path.
462-- | Make the querying function append @path@ to the request path.
434instance (KnownSymbol path, HasClient t m sublayout, Reflex t) => HasClient t m (path :> sublayout) where
463instance (KnownSymbol path, HasClient t m sublayout, Reflex t) => HasClient t m (path :> sublayout) where
435 type Client t m (path :> sublayout) = Client t m sublayout
464 type Client t m (path :> sublayout) = Client t m sublayout
@@ -441,24 +470,29 @@ instance (KnownSymbol path, HasClient t m sublayout, Reflex t) => HasClient t m
441
470
442 where p = symbolVal (Proxy :: Proxy path)
471 where p = symbolVal (Proxy :: Proxy path)
443
472
473+
444instance HasClient t m api => HasClient t m (Vault :> api) where
474instance HasClient t m api => HasClient t m (Vault :> api) where
445 type Client t m (Vault :> api) = Client t m api
475 type Client t m (Vault :> api) = Client t m api
446
476
447 clientWithRoute Proxy q req baseurl =
477 clientWithRoute Proxy q req baseurl =
448 clientWithRoute (Proxy :: Proxy api) q req baseurl
478 clientWithRoute (Proxy :: Proxy api) q req baseurl
449
479
480+
450instance HasClient t m api => HasClient t m (RemoteHost :> api) where
481instance HasClient t m api => HasClient t m (RemoteHost :> api) where
451 type Client t m (RemoteHost :> api) = Client t m api
482 type Client t m (RemoteHost :> api) = Client t m api
452
483
453 clientWithRoute Proxy q req baseurl =
484 clientWithRoute Proxy q req baseurl =
454 clientWithRoute (Proxy :: Proxy api) q req baseurl
485 clientWithRoute (Proxy :: Proxy api) q req baseurl
455
486
487+
488+
456instance HasClient t m api => HasClient t m (IsSecure :> api) where
489instance HasClient t m api => HasClient t m (IsSecure :> api) where
457 type Client t m (IsSecure :> api) = Client t m api
490 type Client t m (IsSecure :> api) = Client t m api
458
491
459 clientWithRoute Proxy q req baseurl =
492 clientWithRoute Proxy q req baseurl =
460 clientWithRoute (Proxy :: Proxy api) q req baseurl
493 clientWithRoute (Proxy :: Proxy api) q req baseurl
461
494
495+
462instance (HasClient t m api, Reflex t)
496instance (HasClient t m api, Reflex t)
463 => HasClient t m (BasicAuth realm usr :> api) where
497 => HasClient t m (BasicAuth realm usr :> api) where
464
498