@@ -18,7 +18,6 @@
1818module Servant.Reflex
1919 ( client
2020 , HasClient(..)
21− , ServantError(..)
2221 , module Servant.Common.BaseUrl
2322 ) where
2423
@@ -29,6 +28,7 @@ import Data.List
2928import Data.Proxy
3029import Data.String.Conversions
3130import Data.Text (unpack)
31+import qualified Data.ByteString.Char8 as BS
3232import GHC.TypeLits
3333-- import Network.HTTP.Media
3434-- import qualified Network.HTTP.Types as H
@@ -36,6 +36,7 @@ import GHC.TypeLits
3636import Servant.API
3737import Servant.Common.BaseUrl
3838import Servant.Common.Req
39+import Servant.API.ContentTypes
3940import Reflex
4041import Reflex.Dom
4142import Reflex.Dom.Xhr
@@ -55,22 +56,23 @@ import Reflex.Dom.Xhr
5556-- -> m (Event t (Either XhrError (Book,Book)))
5657-- > (getAllBooks :<|> postNewBook) = client myApi host
5758-- > where host = constDyn $ BaseUrl Http "localhost" 8080
58−client :: (HasClient t m layout, MonadWidget t m) => Proxy layout -> Dynamic t BaseUrl -> Client t m layout
59−client p baseurl = clientWithRoute p defReq baseurl
59+client :: (HasClient t m layout, MonadWidget t m)
60+ => Proxy layout -> Proxy m -> Dynamic t BaseUrl -> Client t m layout
61+client p q baseurl = clientWithRoute p q defReq baseurl
6062
6163-- | This class lets us define how each API combinator
6264-- influences the creation of an HTTP request. It's mostly
6365-- an internal class, you can just use 'client'.
6466class HasClient t m layout where
6567 type Client t m layout :: *
66− clientWithRoute :: Proxy layout -> Req t -> BaseUrl -> Client t m layout
68+ clientWithRoute :: Proxy layout -> Proxy m -> Req t -> Dynamic t BaseUrl -> Client t m layout
6769
6870
6971instance (HasClient t m a, HasClient t m b) => HasClient t m (a :<|> b) where
7072 type Client t m (a :<|> b) = Client t m a :<|> Client t m b
71− clientWithRoute Proxy req baseurl =
72− clientWithRoute (Proxy :: Proxy a) req baseurl :<|>
73− clientWithRoute (Proxy :: Proxy b) req baseurl
73+ clientWithRoute Proxy q req baseurl =
74+ clientWithRoute (Proxy :: Proxy a) q req baseurl :<|>
75+ clientWithRoute (Proxy :: Proxy b) q req baseurl
7476
7577-- Capture. Example:
7678-- > type MyApi = "books" :> Capture "isbn" Text :> Get '[JSON] Book
@@ -89,25 +91,26 @@ instance (MonadWidget t m, KnownSymbol capture, ToHttpApiData a, HasClient t m s
8991 type Client t m (Capture capture a :> sublayout) =
9092 Behavior t (Maybe a) -> Client t m sublayout
9193
92− clientWithRoute Proxy req baseurl val =
94+ clientWithRoute Proxy q req baseurl val =
9395 clientWithRoute (Proxy :: Proxy sublayout)
96+ q
9497 (prependToPathParts p req)
9598 baseurl
9699
97− where p = fmap (unpack . toUrlPiece) val
100+ where p = (fmap . fmap) (unpack . toUrlPiece) val
98101
99102-- VERB (Returning content) --
100103instance {-# OVERLAPPABLE #-}
101104 -- Note [Non-Empty Content Types]
102− (MimeUnrender ct a, ReflectMethod method, cts' ~ (ct ': cts), MonadWidget t m
105+ (MimeUnrender ct a, FromHttpApiData a, ReflectMethod method, cts' ~ (ct ': cts), MonadWidget t m
103106 ) => HasClient t m (Verb method status cts' a) where
104107 type Client t m (Verb method status cts' a) =
105108 Event t () -> m (Event t (Maybe a, XhrResponse))
106109 -- TODO how to access input types here?
107110 -- ExceptT ServantError IO a
108− clientWithRoute Proxy req baseurl =
111+ clientWithRoute Proxy q req baseurl =
109112 performRequestCT (Proxy :: Proxy ct) method req baseurl
110− where method = reflectMethod (Proxy :: Proxy method)
113+ where method = BS.unpack $ reflectMethod (Proxy :: Proxy method)
111114
112115-- TODO Overlapping error??
113116-- -- VERB (No content) --
@@ -180,12 +183,14 @@ instance (KnownSymbol sym, ToHttpApiData a,
180183 type Client t m (Header sym a :> sublayout) =
181184 Behavior t (Maybe a) -> Client t m sublayout
182185
183− clientWithRoute Proxy req baseurl mval =
186+ clientWithRoute Proxy q req baseurl mval =
184187 clientWithRoute (Proxy :: Proxy sublayout)
185− (maybe req
186− (\value -> Servant.Common.Req.addHeader hname value req)
187− mval
188− )
188+ q
189+ req
190+ -- (maybe req -- TODO Need to pass the header in
191+ -- (\value -> Servant.Common.Req.addHeader hname value req)
192+ -- mval
193+ -- )
189194 baseurl
190195
191196 where hname = symbolVal (Proxy :: Proxy sym)
@@ -198,8 +203,8 @@ instance HasClient t m sublayout
198203 type Client t m (HttpVersion :> sublayout) =
199204 Client t m sublayout
200205
201− clientWithRoute Proxy =
202− clientWithRoute (Proxy :: Proxy sublayout)
206+ clientWithRoute Proxy q =
207+ clientWithRoute (Proxy :: Proxy sublayout) q
203208
204209-- | If you use a 'QueryParam' in one of your endpoints in your API,
205210-- the corresponding querying function will automatically take
@@ -235,14 +240,16 @@ instance (KnownSymbol sym, ToHttpApiData a, HasClient t m sublayout)
235240 Behavior t (Maybe a) -> Client t m sublayout
236241
237242 -- if mparam = Nothing, we don't add it to the query string
238− clientWithRoute Proxy req baseurl mparam =
243+ clientWithRoute Proxy q req baseurl mparam =
239244 clientWithRoute (Proxy :: Proxy sublayout)
240− (req {qParams = (pname', map show mparam) : qParams req})
245+ q
246+ req -- TODO Must pass in the query param
247+ -- (req {qParams = (pname', map show mparam) : qParams req})
241248 baseurl
242249
243− where pname = cs pname'
244− pname' = symbolVal (Proxy :: Proxy sym)
245− mparamText = fmap toQueryParam mparam
250+ -- where pname = cs pname'
251+ -- pname' = symbolVal (Proxy :: Proxy sym)
252+ -- mparamText = fmap toQueryParam mparam
246253
247254-- | If you use a 'QueryParams' in one of your endpoints in your API,
248255-- the corresponding querying function will automatically take
@@ -278,7 +285,7 @@ instance (KnownSymbol sym, ToHttpApiData a, HasClient t m sublayout)
278285 type Client t m (QueryParams sym a :> sublayout) =
279286 [a] -> Client t m sublayout
280287
281− clientWithRoute Proxy req baseurl paramlist = undefined
288+ clientWithRoute Proxy _ req baseurl paramlist = undefined
282289 -- clientWithRoute (Proxy :: Proxy sublayout)
283290 -- (foldl' prependPathParts req paramlist')
284291 -- (foldl' (\ req' -> maybe req' (flip (appendToQueryString pname) req' . Just))
@@ -335,12 +342,15 @@ instance (KnownSymbol sym, ToHttpApiData a, HasClient t m sublayout)
335342-- | Pick a 'Method' and specify where the server you want to query is. You get
336343-- back the full `Response`.
337344-- TODO redo
338−-- instance HasClient Raw where
339−-- type Client Raw = String -> ExceptT ServantError IO (Int, ByteString, MediaType, [HTTP.Header], Response ByteString)
345+instance (MonadWidget t m) => HasClient t m Raw where
346+ type Client t m Raw = Behavior t (Maybe XhrRequest)
347+ -> Event t ()
348+ -> m (Event t XhrResponse)
340349
341−-- clientWithRoute :: Proxy Raw -> Req -> BaseUrl -> Client Raw
342−-- clientWithRoute Proxy req baseurl httpMethod = do
343−-- performRequest httpMethod req baseurl
350+ -- clientWithRoute :: Proxy Raw -> Proxy m -> Req -> BaseUrl -> Client t m Raw
351+ clientWithRoute p q req baseurl xhrs triggers = do
352+ let okReq = fmapMaybe id $ tag xhrs triggers
353+ performRequestAsync okReq
344354
345355-- | If you use a 'ReqBody' in one of your endpoints in your API,
346356-- the corresponding querying function will automatically take
@@ -379,12 +389,12 @@ instance (KnownSymbol sym, ToHttpApiData a, HasClient t m sublayout)
379389-- baseurl
380390
381391-- | Make the querying function append @path@ to the request path.
382−instance (KnownSymbol path, HasClient t m sublayout) => HasClient t m (path :> sublayout) where
392+instance (KnownSymbol path, HasClient t m sublayout, Reflex t) => HasClient t m (path :> sublayout) where
383393 type Client t m (path :> sublayout) = Client t m sublayout
384394
385− clientWithRoute Proxy req baseurl =
386− clientWithRoute (Proxy :: Proxy sublayout)
387− (prependToPathParts (constant p) req)
395+ clientWithRoute Proxy q req baseurl =
396+ clientWithRoute (Proxy :: Proxy sublayout) q
397+ (prependToPathParts (constant (Just p)) req)
388398 baseurl
389399
390400 where p = symbolVal (Proxy :: Proxy path)
@@ -392,26 +402,26 @@ instance (KnownSymbol path, HasClient t m sublayout) => HasClient t m (path :> s
392402instance HasClient t m api => HasClient t m (Vault :> api) where
393403 type Client t m (Vault :> api) = Client t m api
394404
395− clientWithRoute Proxy req baseurl =
396− clientWithRoute (Proxy :: Proxy api) req baseurl
405+ clientWithRoute Proxy q req baseurl =
406+ clientWithRoute (Proxy :: Proxy api) q req baseurl
397407
398408instance HasClient t m api => HasClient t m (RemoteHost :> api) where
399409 type Client t m (RemoteHost :> api) = Client t m api
400410
401− clientWithRoute Proxy req baseurl =
402− clientWithRoute (Proxy :: Proxy api) req baseurl
411+ clientWithRoute Proxy q req baseurl =
412+ clientWithRoute (Proxy :: Proxy api) q req baseurl
403413
404414instance HasClient t m api => HasClient t m (IsSecure :> api) where
405415 type Client t m (IsSecure :> api) = Client t m api
406416
407− clientWithRoute Proxy req baseurl =
408− clientWithRoute (Proxy :: Proxy api) req baseurl
417+ clientWithRoute Proxy q req baseurl =
418+ clientWithRoute (Proxy :: Proxy api) q req baseurl
409419
410420instance HasClient t m subapi =>
411421 HasClient t m (WithNamedConfig name config subapi) where
412422
413423 type Client t m (WithNamedConfig name config subapi) = Client t m subapi
414− clientWithRoute Proxy = clientWithRoute (Proxy :: Proxy subapi)
424+ clientWithRoute Proxy q = clientWithRoute (Proxy :: Proxy subapi) q
415425
416426
417427{- Note [Non-Empty Content Types]