@@ -1,16 +1,24 @@
1−{-# LANGUAGE CPP #-}
1+{-# LANGUAGE AllowAmbiguousTypes #-}
2−{-# LANGUAGE DataKinds #-}
3+{-# LANGUAGE DataKinds #-}
3−{-# LANGUAGE FlexibleContexts #-}
4+{-# LANGUAGE FlexibleContexts #-}
4−{-# LANGUAGE FlexibleInstances #-}
5+{-# LANGUAGE FlexibleInstances #-}
5−{-# LANGUAGE InstanceSigs #-}
6+{-# LANGUAGE InstanceSigs #-}
6−{-# LANGUAGE OverloadedStrings #-}
7+{-# LANGUAGE OverloadedStrings #-}
7−{-# LANGUAGE PolyKinds #-}
8+{-# LANGUAGE PolyKinds #-}
8−{-# LANGUAGE ScopedTypeVariables #-}
9+{-# LANGUAGE ScopedTypeVariables #-}
9−{-# LANGUAGE TupleSections #-}
10+{-# LANGUAGE TupleSections #-}
10−{-# LANGUAGE TypeFamilies #-}
11+{-# LANGUAGE TypeFamilies #-}
11−{-# LANGUAGE TypeOperators #-}
12+{-# LANGUAGE TypeOperators #-}
12−{-# LANGUAGE UndecidableInstances #-}
13+{-# LANGUAGE UndecidableInstances #-}
13{-# LANGUAGE MultiParamTypeClasses #-}
14{-# LANGUAGE MultiParamTypeClasses #-}
15+{-# LANGUAGE OverloadedStrings #-}
16+{-# LANGUAGE PolyKinds #-}
17+{-# LANGUAGE ScopedTypeVariables #-}
18+{-# LANGUAGE TupleSections #-}
19+{-# LANGUAGE TypeFamilies #-}
20+{-# LANGUAGE TypeOperators #-}
21+{-# LANGUAGE UndecidableInstances #-}
15-- #include "overlapping-compat.h"
23-- #include "overlapping-compat.h"
16-- | This module provides 'client' which can automatically generate
24-- | This module provides 'client' which can automatically generate
@@ -18,17 +26,20 @@
19module Servant.Reflex
27module Servant.Reflex
29+ , BuildHeaderKeysTo(..)
21 , HasClient(..)
31 , HasClient(..)
22 , module Servant.Common.Req
32 , module Servant.Common.Req
23 , module Servant.Common.BaseUrl
33 , module Servant.Common.BaseUrl
26−-------------------------------------------------------------------------------
36+------------------------------------------------------------------------------
27import Control.Applicative
37import Control.Applicative
28import Data.Monoid ((<>))
38import Data.Monoid ((<>))
29import qualified Data.Set as Set
39import qualified Data.Set as Set
30import qualified Data.Text.Encoding as E
40import qualified Data.Text.Encoding as E
31import Data.CaseInsensitive (mk)
41import Data.CaseInsensitive (mk)
42+import Data.Functor.Identity
32import Data.Proxy (Proxy (..))
43import Data.Proxy (Proxy (..))
33import qualified Data.Map as Map
44import qualified Data.Map as Map
34import Data.Text (Text)
45import Data.Text (Text)
@@ -43,24 +54,31 @@ import Servant.API ((:<|>)(..),(:>), BasicAuth,
43 QueryParams, Raw, ReflectMethod(..),
54 QueryParams, Raw, ReflectMethod(..),
44 RemoteHost, ReqBody,
55 RemoteHost, ReqBody,
45 ToHttpApiData(..), Vault, Verb)
56 ToHttpApiData(..), Vault, Verb)
58+import Reflex.Dom (Dynamic, Event, Reflex,
60+ XhrResponseHeaders(..),
61+ XhrResponse(..), attachPromptlyDynWith, constDyn, ffor, fmapMaybe,
62+ leftmost, performRequestsAsync,
64+------------------------------------------------------------------------------
46import Servant.Common.BaseUrl (BaseUrl(..), Scheme(..), baseUrlWidget,
65import Servant.Common.BaseUrl (BaseUrl(..), Scheme(..), baseUrlWidget,
47 showBaseUrl,
66 showBaseUrl,
48 SupportsServantReflex)
67 SupportsServantReflex)
49import Servant.Common.Req (Req, ReqResult(..), QParam(..),
68import Servant.Common.Req (Req, ReqResult(..), QParam(..),
50 QueryPart(..), addHeader, authData,
69 QueryPart(..), addHeader, authData,
51− defReq, prependToPathParts,
70+ defReq, evalResponse, prependToPathParts,
52− performRequestCT,
71+ -- performRequestCT,
53− performRequestNoBody,
73+ -- performRequestNoBody,
74+ performRequestsNoBody,
75+ performSomeRequestsAsync,
54 qParamToQueryPart, reqBody,
76 qParamToQueryPart, reqBody,
55 reqSuccess, reqFailure,
77 reqSuccess, reqFailure,
56 reqMethod, respHeaders, response,
78 reqMethod, respHeaders, response,
58−import Reflex.Dom (Dynamic, Event, Reflex,
81+
60− XhrResponseHeaders(..),
61− XhrResponse(..), ffor, fmapMaybe,
62− leftmost, performRequestAsync,
65-- * Accessing APIs as a Client
83-- * Accessing APIs as a Client
@@ -72,28 +90,31 @@ import Reflex.Dom (Dynamic, Event, Reflex,
72-- > myApi :: Proxy MyApi
90-- > myApi :: Proxy MyApi
73-- > myApi = Proxy
91-- > myApi = Proxy
75−-- > getAllBooks :: Event t () -> m (Event t (Either XhrError ((),[Book])))
93+-- > getAllBooks :: Event t l -> m (Event t (l, ReqResult [Book]))
76−-- > postNewBook :: Dynamic t (Maybe Book) -> Event t ()
94+-- > postNewBook :: Dynamic t (Maybe Book) -> Event t l
77−-- -> m (Event t (Either XhrError (Book,Book)))
95+-- -> m (Event t (l, ReqResult Book)))
78-- > (getAllBooks :<|> postNewBook) = client myApi host
96-- > (getAllBooks :<|> postNewBook) = client myApi host
79-- > where host = constDyn $ BaseUrl Http "localhost" 8080
97-- > where host = constDyn $ BaseUrl Http "localhost" 8080
80−client :: (HasClient t m layout)
98+client :: (HasClient t m layout tag)
81− => Proxy layout -> Proxy m -> Dynamic t BaseUrl -> Client t m layout
99+ => Proxy layout -> Proxy m -> Proxy tag -> Dynamic t BaseUrl -> Client t m layout tag
82−client p q baseurl = clientWithRoute p q defReq baseurl
100+client p q t baseurl = clientWithRoute p q t defReq baseurl
84-- | This class lets us define how each API combinator
103-- | This class lets us define how each API combinator
85-- influences the creation of an HTTP request. It's mostly
104-- influences the creation of an HTTP request. It's mostly
86-- an internal class, you can just use 'client'.
105-- an internal class, you can just use 'client'.
87−class HasClient t m layout where
106+class HasClient t m layout (tag :: *) where
88− type Client t m layout :: *
107+ type Client t m layout tag :: *
89− clientWithRoute :: Proxy layout -> Proxy m -> Req t -> Dynamic t BaseUrl -> Client t m layout
108+ clientWithRoute :: Proxy layout -> Proxy m -> Proxy tag -> Req t -> Dynamic t BaseUrl -> Client t m layout tag
92−instance (HasClient t m a, HasClient t m b) => HasClient t m (a :<|> b) where
111+instance (HasClient t m a tag, HasClient t m b tag) => HasClient t m (a :<|> b) tag where
93− type Client t m (a :<|> b) = Client t m a :<|> Client t m b
112+ type Client t m (a :<|> b) tag = Client t m a tag :<|> Client t m b tag
94− clientWithRoute Proxy q req baseurl =
114+ clientWithRoute Proxy q pTag req baseurl =
95− clientWithRoute (Proxy :: Proxy a) q req baseurl :<|>
115+ clientWithRoute (Proxy :: Proxy a) q pTag req baseurl :<|>
96− clientWithRoute (Proxy :: Proxy b) q req baseurl
116+ clientWithRoute (Proxy :: Proxy b) q pTag req baseurl
98-- Capture. Example:
119-- Capture. Example:
99-- > type MyApi = "books" :> Capture "isbn" Text :> Get '[JSON] Book
120-- > type MyApi = "books" :> Capture "isbn" Text :> Get '[JSON] Book
@@ -103,50 +124,54 @@ instance (HasClient t m a, HasClient t m b) => HasClient t m (a :<|> b) where
103-- > getBook :: SupportsServantReflex t m
124-- > getBook :: SupportsServantReflex t m
104-- => Dynamic t BaseUrl
125-- => Dynamic t BaseUrl
105-- -> Dynamic t (Maybe Text)
126-- -> Dynamic t (Maybe Text)
106−-- -> Event t ()
127+-- -> Event t l
107−-- -> m (Event t (Either XhrError (Text, Book)))
128+-- -> m (Event t (l, ReqResult Book))
108-- > getBook = client myApi (constDyn host)
129-- > getBook = client myApi (constDyn host)
109−instance (SupportsServantReflex t m, ToHttpApiData a, HasClient t m sublayout)
110− => HasClient t m (Capture capture a :> sublayout) where
131+instance (SupportsServantReflex t m, ToHttpApiData a, HasClient t m sublayout tag)
132+ => HasClient t m (Capture capture a :> sublayout) tag where
112− type Client t m (Capture capture a :> sublayout) =
134+ type Client t m (Capture capture a :> sublayout) tag =
113− Dynamic t (Either Text a) -> Client t m sublayout
135+ Dynamic t (Either Text a) -> Client t m sublayout tag
115− clientWithRoute Proxy q req baseurl val =
137+ clientWithRoute Proxy q t req baseurl val =
116 clientWithRoute (Proxy :: Proxy sublayout)
138 clientWithRoute (Proxy :: Proxy sublayout)
118 (prependToPathParts p req)
140 (prependToPathParts p req)
121 where p = (fmap . fmap) (toUrlPiece) val
142 where p = (fmap . fmap) (toUrlPiece) val
123-- VERB (Returning content) --
145-- VERB (Returning content) --
124instance {-# OVERLAPPABLE #-}
146instance {-# OVERLAPPABLE #-}
125 -- Note [Non-Empty Content Types]
147 -- Note [Non-Empty Content Types]
126 (MimeUnrender ct a, ReflectMethod method, cts' ~ (ct ': cts), SupportsServantReflex t m
148 (MimeUnrender ct a, ReflectMethod method, cts' ~ (ct ': cts), SupportsServantReflex t m
127− ) => HasClient t m (Verb method status cts' a) where
149+ ) => HasClient t m (Verb method status cts' a) tag where
128− type Client t m (Verb method status cts' a) =
150+ type Client t m (Verb method status cts' a) tag =
129− Event t () -> m (Event t (ReqResult a))
151+ Event t tag -> m (Event t (ReqResult tag a))
130 -- TODO how to access input types here?
152 -- TODO how to access input types here?
131 -- ExceptT ServantError IO a
153 -- ExceptT ServantError IO a
132− clientWithRoute Proxy _ req baseurl =
154+ clientWithRoute Proxy _ _ req baseurl trigs =
133− performRequestCT (Proxy :: Proxy ct) method req' baseurl
155+ -- performRequestCT (Proxy :: Proxy ct) method req' baseurl trigs
156+ fmap runIdentity <$> performRequestsCT (Proxy :: Proxy ct) method (constDyn $ Identity $ req') baseurl trigs
134 where method = E.decodeUtf8 $ reflectMethod (Proxy :: Proxy method)
157 where method = E.decodeUtf8 $ reflectMethod (Proxy :: Proxy method)
135 req' = req { reqMethod = method }
158 req' = req { reqMethod = method }
137-- -- VERB (No content) --
161-- -- VERB (No content) --
138instance {-# OVERLAPPING #-}
162instance {-# OVERLAPPING #-}
139 (ReflectMethod method, SupportsServantReflex t m) =>
163 (ReflectMethod method, SupportsServantReflex t m) =>
140− HasClient t m (Verb method status cts NoContent) where
164+ HasClient t m (Verb method status cts NoContent) tag where
141− type Client t m (Verb method status cts NoContent) =
165+ type Client t m (Verb method status cts NoContent) tag =
142− Event t () -> m (Event t (ReqResult NoContent))
166+ Event t tag -> m (Event t (ReqResult tag NoContent))
143 -- TODO: how to access input types here?
167 -- TODO: how to access input types here?
144 -- ExceptT ServantError IO NoContent
168 -- ExceptT ServantError IO NoContent
145− clientWithRoute Proxy _ req baseurl =
169+ clientWithRoute Proxy _ _ req baseurl =
146− performRequestNoBody method req baseurl
170+ (fmap . fmap) runIdentity . performRequestsNoBody method (constDyn $ Identity req) baseurl
147 where method = E.decodeUtf8 $ reflectMethod (Proxy :: Proxy method)
171 where method = E.decodeUtf8 $ reflectMethod (Proxy :: Proxy method)
149−toHeaders :: BuildHeadersTo ls => ReqResult a -> ReqResult (Headers ls a)
174+toHeaders :: BuildHeadersTo ls => ReqResult tag a -> ReqResult tag (Headers ls a)
150toHeaders r =
175toHeaders r =
151 let toBS = E.encodeUtf8
176 let toBS = E.encodeUtf8
152 hdrs = maybe []
177 hdrs = maybe []
@@ -162,8 +187,8 @@ instance {-# OVERLAPPABLE #-} BuildHeaderKeysTo '[]
162 where buildHeaderKeysTo _ = []
187 where buildHeaderKeysTo _ = []
164instance {-# OVERLAPPABLE #-} (BuildHeaderKeysTo xs, KnownSymbol h)
189instance {-# OVERLAPPABLE #-} (BuildHeaderKeysTo xs, KnownSymbol h)
165− => BuildHeaderKeysTo '[(Header h v) ': xs] where
190+ => BuildHeaderKeysTo ((Header h v) ': xs) where
166− buildHeaderKeysTo _ = (T.pack $ symbolVal (Proxy :: Proxy h)) : buildHeaderKeysTo (Proxy :: Proxy xs)
191+ buildHeaderKeysTo _ = T.pack (symbolVal (Proxy :: Proxy h)) : buildHeaderKeysTo (Proxy :: Proxy xs)
168-- HEADERS Verb (Content) --
193-- HEADERS Verb (Content) --
169-- Headers combinator not treated in fully general case,
194-- Headers combinator not treated in fully general case,
@@ -175,33 +200,35 @@ instance {-# OVERLAPPABLE #-}
175 ( MimeUnrender ct a, BuildHeadersTo ls, BuildHeaderKeysTo ls,
200 ( MimeUnrender ct a, BuildHeadersTo ls, BuildHeaderKeysTo ls,
176 ReflectMethod method, cts' ~ (ct ': cts),
201 ReflectMethod method, cts' ~ (ct ': cts),
177 SupportsServantReflex t m
202 SupportsServantReflex t m
178− ) => HasClient t m (Verb method status cts' (Headers ls a)) where
203+ ) => HasClient t m (Verb method status cts' (Headers ls a)) tag where
179− type Client t m (Verb method status cts' (Headers ls a)) =
204+ type Client t m (Verb method status cts' (Headers ls a)) tag =
180− Event t () -> m (Event t (ReqResult (Headers ls a)))
205+ Event t tag -> m (Event t (ReqResult tag (Headers ls a)))
181− clientWithRoute Proxy _ req baseurl = do
206+ clientWithRoute Proxy _ _ req baseurl trigs = do
182 let method = E.decodeUtf8 $ reflectMethod (Proxy :: Proxy method)
207 let method = E.decodeUtf8 $ reflectMethod (Proxy :: Proxy method)
183− resp <- performRequestCT (Proxy :: Proxy ct) method req' baseurl
208+ resp <- fmap runIdentity <$> performRequestsCT (Proxy :: Proxy ct) method (constDyn $ Identity req') baseurl trigs
184− return $ (fmap . fmap) toHeaders resp
209+ return $ toHeaders <$> resp
185 where req' = req { respHeaders =
210 where req' = req { respHeaders =
186 OnlyHeaders (Set.fromList (buildHeaderKeysTo (Proxy :: Proxy ls)))
211 OnlyHeaders (Set.fromList (buildHeaderKeysTo (Proxy :: Proxy ls)))
189-- HEADERS Verb (No content) --
215-- HEADERS Verb (No content) --
190instance {-# OVERLAPPABLE #-}
216instance {-# OVERLAPPABLE #-}
191 ( BuildHeadersTo ls, BuildHeaderKeysTo ls, ReflectMethod method,
217 ( BuildHeadersTo ls, BuildHeaderKeysTo ls, ReflectMethod method,
192 SupportsServantReflex t m
218 SupportsServantReflex t m
193− ) => HasClient t m (Verb method status cts (Headers ls NoContent)) where
219+ ) => HasClient t m (Verb method status cts (Headers ls NoContent)) tag where
194− type Client t m (Verb method status cts (Headers ls NoContent))
220+ type Client t m (Verb method status cts (Headers ls NoContent)) tag
195− = Event t () -> m (Event t (ReqResult (Headers ls NoContent)))
221+ = Event t tag -> m (Event t (ReqResult tag (Headers ls NoContent)))
196− clientWithRoute Proxy _ req baseurl = do
222+ clientWithRoute Proxy _ _ req baseurl trigs = do
197 let method = E.decodeUtf8 $ reflectMethod (Proxy :: Proxy method)
223 let method = E.decodeUtf8 $ reflectMethod (Proxy :: Proxy method)
198− resp <- performRequestNoBody method req' baseurl
224+ resp <- fmap runIdentity <$> performRequestsNoBody method (constDyn $ Identity req') baseurl trigs
199− return $ (fmap . fmap) toHeaders resp
225+ return $ toHeaders <$> resp
200 where req' = req {respHeaders =
226 where req' = req {respHeaders =
201 OnlyHeaders (Set.fromList (buildHeaderKeysTo (Proxy :: Proxy ls)))
227 OnlyHeaders (Set.fromList (buildHeaderKeysTo (Proxy :: Proxy ls)))
206-- > newtype Referer = Referer { referrer :: Text }
233-- > newtype Referer = Referer { referrer :: Text }
207-- > deriving (Eq, Show, Generic, FromText, ToHttpApiData)
234-- > deriving (Eq, Show, Generic, FromText, ToHttpApiData)
@@ -216,29 +243,32 @@ instance {-# OVERLAPPABLE #-}
216-- > -- then you can just use "viewRefer" to query that endpoint
243-- > -- then you can just use "viewRefer" to query that endpoint
217-- > -- specifying Nothing or e.g Just "http://haskell.org/" as arguments
244-- > -- specifying Nothing or e.g Just "http://haskell.org/" as arguments
218instance (KnownSymbol sym, ToHttpApiData a,
245instance (KnownSymbol sym, ToHttpApiData a,
219− HasClient t m sublayout, SupportsServantReflex t m)
246+ HasClient t m sublayout tag, SupportsServantReflex t m)
220− => HasClient t m (Header sym a :> sublayout) where
247+ => HasClient t m (Header sym a :> sublayout) tag where
222− type Client t m (Header sym a :> sublayout) =
249+ type Client t m (Header sym a :> sublayout) tag =
223− Dynamic t (Either Text a) -> Client t m sublayout
250+ Dynamic t (Either Text a) -> Client t m sublayout tag
225− clientWithRoute Proxy q req baseurl eVal =
252+ clientWithRoute Proxy q t req baseurl eVal =
226 clientWithRoute (Proxy :: Proxy sublayout)
253 clientWithRoute (Proxy :: Proxy sublayout)
228 (Servant.Common.Req.addHeader hname eVal req)
255 (Servant.Common.Req.addHeader hname eVal req)
230 where hname = T.pack $ symbolVal (Proxy :: Proxy sym)
257 where hname = T.pack $ symbolVal (Proxy :: Proxy sym)
232-- | Using a 'HttpVersion' combinator in your API doesn't affect the client
262-- | Using a 'HttpVersion' combinator in your API doesn't affect the client
233-- functions.
263-- functions.
234−instance HasClient t m sublayout
264+instance HasClient t m sublayout tag
235− => HasClient t m (HttpVersion :> sublayout) where
265+ => HasClient t m (HttpVersion :> sublayout) tag where
237− type Client t m (HttpVersion :> sublayout) =
267+ type Client t m (HttpVersion :> sublayout) tag =
238− Client t m sublayout
268+ Client t m sublayout tag
240− clientWithRoute Proxy q =
270+ clientWithRoute Proxy q t =
241− clientWithRoute (Proxy :: Proxy sublayout) q
271+ clientWithRoute (Proxy :: Proxy sublayout) q t
244-- | If you use a 'QueryParam' in one of your endpoints in your API,
274-- | If you use a 'QueryParam' in one of your endpoints in your API,
@@ -267,15 +297,15 @@ instance HasClient t m sublayout
267-- > -- then you can just use "getBooksBy" to query that endpoint.
297-- > -- then you can just use "getBooksBy" to query that endpoint.
268-- > -- 'getBooksBy Nothing' for all books
298-- > -- 'getBooksBy Nothing' for all books
269-- > -- 'getBooksBy (Just "Isaac Asimov")' to get all books by Isaac Asimov
299-- > -- 'getBooksBy (Just "Isaac Asimov")' to get all books by Isaac Asimov
270−instance (KnownSymbol sym, ToHttpApiData a, HasClient t m sublayout, Reflex t)
300+instance (KnownSymbol sym, ToHttpApiData a, HasClient t m sublayout tag, Reflex t)
271− => HasClient t m (QueryParam sym a :> sublayout) where
301+ => HasClient t m (QueryParam sym a :> sublayout) tag where
273− type Client t m (QueryParam sym a :> sublayout) =
303+ type Client t m (QueryParam sym a :> sublayout) tag =
274− Dynamic t (QParam a) -> Client t m sublayout
304+ Dynamic t (QParam a) -> Client t m sublayout tag
276 -- if mparam = Nothing, we don't add it to the query string
306 -- if mparam = Nothing, we don't add it to the query string
277− clientWithRoute Proxy q req baseurl mparam =
307+ clientWithRoute Proxy q t req baseurl mparam =
278− clientWithRoute (Proxy :: Proxy sublayout) q
308+ clientWithRoute (Proxy :: Proxy sublayout) q t
279 (req {qParams = paramPair : qParams req}) baseurl
309 (req {qParams = paramPair : qParams req}) baseurl
281 where pname = symbolVal (Proxy :: Proxy sym)
311 where pname = symbolVal (Proxy :: Proxy sym)
@@ -284,6 +314,8 @@ instance (KnownSymbol sym, ToHttpApiData a, HasClient t m sublayout, Reflex t)
284 p prm = QueryPartParam $ fmap qParamToQueryPart prm -- (fmap . fmap) (unpack . toQueryParam) prm
314 p prm = QueryPartParam $ fmap qParamToQueryPart prm -- (fmap . fmap) (unpack . toQueryParam) prm
285 paramPair = (T.pack pname, p mparam)
315 paramPair = (T.pack pname, p mparam)
287-- | If you use a 'QueryParams' in one of your endpoints in your API,
319-- | If you use a 'QueryParams' in one of your endpoints in your API,
288-- the corresponding querying function will automatically take
320-- the corresponding querying function will automatically take
289-- an additional argument, a list of values of the type specified
321-- an additional argument, a list of values of the type specified
@@ -312,21 +344,22 @@ instance (KnownSymbol sym, ToHttpApiData a, HasClient t m sublayout, Reflex t)
312-- > -- 'getBooksBy []' for all books
344-- > -- 'getBooksBy []' for all books
313-- > -- 'getBooksBy ["Isaac Asimov", "Robert A. Heinlein"]'
345-- > -- 'getBooksBy ["Isaac Asimov", "Robert A. Heinlein"]'
314-- > -- to get all books by Asimov and Heinlein
346-- > -- to get all books by Asimov and Heinlein
315−instance (KnownSymbol sym, ToHttpApiData a, HasClient t m sublayout, Reflex t)
347+instance (KnownSymbol sym, ToHttpApiData a, HasClient t m sublayout tag, Reflex t)
316− => HasClient t m (QueryParams sym a :> sublayout) where
348+ => HasClient t m (QueryParams sym a :> sublayout) tag where
318− type Client t m (QueryParams sym a :> sublayout) =
350+ type Client t m (QueryParams sym a :> sublayout) tag =
319− Dynamic t [a] -> Client t m sublayout
351+ Dynamic t [a] -> Client t m sublayout tag
321− clientWithRoute Proxy q req baseurl paramlist =
353+ clientWithRoute Proxy q t req baseurl paramlist =
322− clientWithRoute (Proxy :: Proxy sublayout) q req' baseurl
354+ clientWithRoute (Proxy :: Proxy sublayout) q t req' baseurl
324 where req' = req { qParams = (T.pack pname, params') : qParams req }
356 where req' = req { qParams = (T.pack pname, params') : qParams req }
325 pname = symbolVal (Proxy :: Proxy sym)
357 pname = symbolVal (Proxy :: Proxy sym)
326− params' = QueryPartParams $ (fmap . fmap) (toQueryParam)
358+ params' = QueryPartParams $ (fmap . fmap) toQueryParam
327 paramlist
359 paramlist
330-- | If you use a 'QueryFlag' in one of your endpoints in your API,
363-- | If you use a 'QueryFlag' in one of your endpoints in your API,
331-- the corresponding querying function will automatically take
364-- the corresponding querying function will automatically take
332-- an additional 'Bool' argument.
365-- an additional 'Bool' argument.
@@ -351,49 +384,42 @@ instance (KnownSymbol sym, ToHttpApiData a, HasClient t m sublayout, Reflex t)
351-- > -- 'getBooksBy True' to only get _already published_ books
384-- > -- 'getBooksBy True' to only get _already published_ books
353-- TODO Bring back
386-- TODO Bring back
354−instance (KnownSymbol sym, HasClient t m sublayout, Reflex t)
387+instance (KnownSymbol sym, HasClient t m sublayout tag, Reflex t)
355− => HasClient t m (QueryFlag sym :> sublayout) where
388+ => HasClient t m (QueryFlag sym :> sublayout) tag where
357− type Client t m (QueryFlag sym :> sublayout) =
390+ type Client t m (QueryFlag sym :> sublayout) tag =
358− Dynamic t Bool -> Client t m sublayout
391+ Dynamic t Bool -> Client t m sublayout tag
360− clientWithRoute Proxy q req baseurl flag =
393+ clientWithRoute Proxy q t req baseurl flag =
361− clientWithRoute (Proxy :: Proxy sublayout) q req' baseurl
394+ clientWithRoute (Proxy :: Proxy sublayout) q t req' baseurl
363 where req' = req { qParams = thisPair : qParams req }
396 where req' = req { qParams = thisPair : qParams req }
364 thisPair = (T.pack pName, QueryPartFlag flag) :: (Text, QueryPart t)
397 thisPair = (T.pack pName, QueryPartFlag flag) :: (Text, QueryPart t)
365 pName = symbolVal (Proxy :: Proxy sym)
398 pName = symbolVal (Proxy :: Proxy sym)
368−-- | Pick a 'Method' and specify where the server you want to query is. You get
401+
369−-- back the full `Response`.
402+-- | Send a raw 'XhrRequest ()' directly to 'baseurl'
371−instance SupportsServantReflex t m => HasClient t m Raw where
403+instance SupportsServantReflex t m => HasClient t m Raw tag where
372− type Client t m Raw = Dynamic t (Either Text (XhrRequest ()))
404+ type Client t m Raw tag = Dynamic t (Either Text (XhrRequest ()))
373− -> Event t ()
405+ -> Event t tag
374− -> m (Event t (ReqResult ()))
406+ -> m (Event t (ReqResult tag ()))
376− -- clientWithRoute :: Proxy Raw -> Proxy m -> Req -> BaseUrl -> Client t m Raw
377− clientWithRoute _ _ _ baseurl xhrs triggers = do
408+ clientWithRoute _ _ _ _ baseurl xhrs triggers = do
378− let xhrs' = liftA2 (\x path -> case x of
410+ let xhrs' = liftA2 (\x path -> case x of
379− Left e -> Left e
411+ Left e -> Left e
380− Right jx -> Right $ jx {_xhrRequest_url = path
412+ Right jx -> Right $ jx { _xhrRequest_url = path <> _xhrRequest_url jx }
381− <> _xhrRequest_url jx})
383− (showBaseUrl <$> baseurl)
413+ ) xhrs (showBaseUrl <$> baseurl)
384− reqs = tagPromptlyDyn xhrs' triggers
414+ xhrs'' = attachPromptlyDynWith (flip (,)) xhrs' triggers :: Event t (tag, Either Text (XhrRequest ()))
385− okReq = fmapMaybe hush reqs
415+ badReq = fmapMaybe (\(t,x) -> either (Just . (t,)) (const Nothing) x) xhrs'' :: Event t (tag, Text)
386− badReq = fmapMaybe tattle reqs
416+ okReq = fmapMaybe (\(t,x) -> either (const Nothing) (Just . (t,)) x) xhrs'' :: Event t (tag, XhrRequest ())
387− resps <- performRequestAsync okReq
417+
388− return $ leftmost [fmap (ResponseSuccess () ) resps
418+ resps <- performRequestsAsync okReq
389− ,fmap RequestFailure badReq]
419+ return $ leftmost [ uncurry RequestFailure <$> badReq
390−
420+ , evalResponse (const $ Right ()) <$> resps
392−hush :: Either e a -> Maybe a
422+
393−hush = either (const Nothing) Just
395−tattle :: Either e a -> Maybe e
396−tattle = either Just (const Nothing)
398-- | If you use a 'ReqBody' in one of your endpoints in your API,
424-- | If you use a 'ReqBody' in one of your endpoints in your API,
399-- the corresponding querying function will automatically take
425-- the corresponding querying function will automatically take
@@ -415,14 +441,14 @@ tattle = either Just (const Nothing)
415-- > where host = BaseUrl Http "localhost" 8080
441-- > where host = BaseUrl Http "localhost" 8080
416-- > -- then you can just use "addBook" to query that endpoint
442-- > -- then you can just use "addBook" to query that endpoint
418−instance (MimeRender ct a, HasClient t m sublayout, Reflex t)
444+instance (MimeRender ct a, HasClient t m sublayout tag, Reflex t)
419− => HasClient t m (ReqBody (ct ': cts) a :> sublayout) where
445+ => HasClient t m (ReqBody (ct ': cts) a :> sublayout) tag where
421− type Client t m (ReqBody (ct ': cts) a :> sublayout) =
447+ type Client t m (ReqBody (ct ': cts) a :> sublayout) tag =
422− Dynamic t (Either Text a) -> Client t m sublayout
448+ Dynamic t (Either Text a) -> Client t m sublayout tag
424− clientWithRoute Proxy q req baseurl body =
450+ clientWithRoute Proxy q t req baseurl body =
425− clientWithRoute (Proxy :: Proxy sublayout) q req' baseurl
451+ clientWithRoute (Proxy :: Proxy sublayout) q t req' baseurl
426 where req' = req { reqBody = bodyBytesCT }
452 where req' = req { reqBody = bodyBytesCT }
427 ctProxy = Proxy :: Proxy ct
453 ctProxy = Proxy :: Proxy ct
428 ctString = T.pack $ show $ contentType ctProxy
454 ctString = T.pack $ show $ contentType ctProxy
@@ -430,43 +456,49 @@ instance (MimeRender ct a, HasClient t m sublayout, Reflex t)
430 (\b -> (mimeRender ctProxy b, ctString))
456 (\b -> (mimeRender ctProxy b, ctString))
433-- | Make the querying function append @path@ to the request path.
461-- | Make the querying function append @path@ to the request path.
434−instance (KnownSymbol path, HasClient t m sublayout, Reflex t) => HasClient t m (path :> sublayout) where
462+instance (KnownSymbol path, HasClient t m sublayout tag, Reflex t) => HasClient t m (path :> sublayout) tag where
435− type Client t m (path :> sublayout) = Client t m sublayout
463+ type Client t m (path :> sublayout) tag = Client t m sublayout tag
437− clientWithRoute Proxy q req baseurl =
465+ clientWithRoute Proxy q t req baseurl =
438− clientWithRoute (Proxy :: Proxy sublayout) q
466+ clientWithRoute (Proxy :: Proxy sublayout) q t
439− (prependToPathParts (pure (Right $ T.pack p)) req)
467+ (prependToPathParts (pure (Right $ T.pack p)) req) baseurl
442 where p = symbolVal (Proxy :: Proxy path)
469 where p = symbolVal (Proxy :: Proxy path)
444−instance HasClient t m api => HasClient t m (Vault :> api) where
445− type Client t m (Vault :> api) = Client t m api
472+instance HasClient t m api tag => HasClient t m (Vault :> api) tag where
473+ type Client t m (Vault :> api) tag = Client t m api tag
447− clientWithRoute Proxy q req baseurl =
475+ clientWithRoute Proxy q t req baseurl =
448− clientWithRoute (Proxy :: Proxy api) q req baseurl
476+ clientWithRoute (Proxy :: Proxy api) q t req baseurl
479+instance HasClient t m api tag => HasClient t m (RemoteHost :> api) tag where
480+ type Client t m (RemoteHost :> api) tag = Client t m api tag
482+ clientWithRoute Proxy q t req baseurl =
483+ clientWithRoute (Proxy :: Proxy api) q t req baseurl
450−instance HasClient t m api => HasClient t m (RemoteHost :> api) where
451− type Client t m (RemoteHost :> api) = Client t m api
453− clientWithRoute Proxy q req baseurl =
487+instance HasClient t m api tag => HasClient t m (IsSecure :> api) tag where
454− clientWithRoute (Proxy :: Proxy api) q req baseurl
488+ type Client t m (IsSecure :> api) tag = Client t m api tag
456−instance HasClient t m api => HasClient t m (IsSecure :> api) where
490+ clientWithRoute Proxy q t req baseurl =
457− type Client t m (IsSecure :> api) = Client t m api
491+ clientWithRoute (Proxy :: Proxy api) q t req baseurl
459− clientWithRoute Proxy q req baseurl =
460− clientWithRoute (Proxy :: Proxy api) q req baseurl
462−instance (HasClient t m api, Reflex t)
494+instance (HasClient t m api tag, Reflex t)
463− => HasClient t m (BasicAuth realm usr :> api) where
495+ => HasClient t m (BasicAuth realm usr :> api) tag where
465− type Client t m (BasicAuth realm usr :> api) = Dynamic t (Maybe BasicAuthData)
497+ type Client t m (BasicAuth realm usr :> api) tag = Dynamic t (Maybe BasicAuthData)
466− -> Client t m api
498+ -> Client t m api tag
468− clientWithRoute Proxy q req baseurl authdata =
500+ clientWithRoute Proxy q t req baseurl authdata =
469− clientWithRoute (Proxy :: Proxy api) q req' baseurl
501+ clientWithRoute (Proxy :: Proxy api) q t req' baseurl
471 req' = req { authData = Just authdata }
503 req' = req { authData = Just authdata }