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