@@ -19,12 +19,16 @@
20module Servant.Reflex.RequestAPI where
20module Servant.Reflex.RequestAPI where
22+import Control.Arrow (first, second)
22import Control.Lens
23import Control.Lens
23import Data.Generics.Product
24import Data.Generics.Product
24import Data.Proxy
25import Data.Proxy
26+import Data.CaseInsensitive (mk)
27+import qualified Data.List as L
25import qualified Data.Map as M
28import qualified Data.Map as M
26import Data.Maybe (catMaybes)
29import Data.Maybe (catMaybes)
27import Data.Semigroup ((<>))
30import Data.Semigroup ((<>))
31+import qualified Data.Set as Set
28import qualified Data.Text.Encoding as E
32import qualified Data.Text.Encoding as E
29import Data.Text (Text)
33import Data.Text (Text)
30import qualified Data.Text as T
34import qualified Data.Text as T
@@ -39,23 +43,61 @@ import Servant.Common.BaseUrl
40import Reflex.Dom hiding (HList(..))
44import Reflex.Dom hiding (HList(..))
46+import Servant.Reflex (BuildHeaderKeysTo (..), toHeaders)
53+ - [x] Verb (Headers content)
54+ - [x] Verb (Headers nocontent)
57+ - [ ] Capture' :> ...
58+ - [x] CaptureAll :> ...
59+ - [x] QueryParam :> ...
60+ - [x] QueryParams :> ...
61+ - [x] QueryFlag :> ...
66+ - [x] Description :> ...
68+ - [ ] RemoteHost :> ...
69+ - [x] IsSecure :> ...
71+ - [ ] WithNamedContext :> ...
72+ - [ ] AuthenticatedRequest :> ...
73+ - [x] BasicAuth :> ...
74+ - [ ] EmptyClient :> ...
76+ - [ ] HttpVersion :> ...
42data HList xs where
78data HList xs where
43 HNil :: HList '[]
79 HNil :: HList '[]
44 HCons :: x -> HList xs -> HList (x ': xs)
80 HCons :: x -> HList xs -> HList (x ': xs)
46−clientR :: forall t m layout f tag. (HasClientR t m (Seal layout) f tag, Applicative f, Reflex t)
82+clientR :: forall t m layout f . (HasClientR t m (Seal layout) f, Applicative f, Reflex t)
47− => Proxy layout -> Proxy (m :: * -> *) -> Proxy t -> Proxy f -> Proxy tag
83+ => Proxy layout -> Proxy (m :: * -> *) -> Proxy t -> Proxy f
48− -> Dynamic t BaseUrl -> ClientR t m (Seal layout) f tag
84+ -> Dynamic t BaseUrl -> ClientR t m (Seal layout) f
49−clientR _ mP tP fP tagP url =
85+clientR _ mP tP fP url =
50− clientRWithRoute (Proxy :: Proxy (Seal layout)) mP fP tagP undefined url undefined
86+ clientRWithRoute (Proxy :: Proxy (Seal layout)) mP fP undefined url undefined
52-- | A class for generating top-level the API client function
88-- | A class for generating top-level the API client function
53−class HasClientR t (m :: * -> *) api (f :: * -> *) tag where
89+class HasClientR t (m :: * -> *) api (f :: * -> *) where
54− type ClientR t m api f tag :: *
90+ type ClientR t m api f :: *
55− clientRWithRoute :: Proxy api -> Proxy m -> Proxy f -> Proxy tag
91+ clientRWithRoute :: Proxy api -> Proxy m -> Proxy f
56 -> Dynamic t (f (Req t)) -> Dynamic t BaseUrl
92 -> Dynamic t (f (Req t)) -> Dynamic t BaseUrl
57− -> ClientOptions -> ClientR t m api f tag
93+ -> ClientOptions -> ClientR t m api f
95+-- instance EndpointR t m Raw f where
96+-- type EInputs t m Raw f = '[XhrRequest T.Text]
97+-- type EOutput t m Raw f = XhrResponse
99+-- mkReq (HCons (XhrRequest method url conf) NHil) =
61-- | A class for generating endpoint-level API client functions
103-- | A class for generating endpoint-level API client functions
@@ -68,42 +110,34 @@ class HasClientR t (m :: * -> *) api (f :: * -> *) tag where
68-- sequences of @:<|>@ combinators, such a listing doesn't make
110-- sequences of @:<|>@ combinators, such a listing doesn't make
69-- sense. So, we use one class for endpoint-level recursion and
111-- sense. So, we use one class for endpoint-level recursion and
70-- another for collecting endpoints into the top-level API
112-- another for collecting endpoints into the top-level API
71−class EndpointR t m api f tag where
113+class EndpointR t m api f where
73− type EndpointResult t m api f tag :: *
74− type EInputs t m api f tag :: [*]
75− type EOutput t m api f tag :: *
77− mkReq :: HList (EInputs t m api f tag) -> ReqR
115+ type EInputs t m api f :: [*]
78− getResp :: XhrResponse -> EOutput t m api f tag
116+ type EOutput t m api f :: *
80− eInputs :: HList (EInputs t m api f tag)
118+ mkReq :: HList (EInputs t m api f) -> ReqR
81− clientEndpoint :: Proxy api -> Proxy m -> Proxy f -> Proxy tag
119+ getResp :: XhrResponse -> EOutput t m api f
82− -> f ReqR -> Dynamic t BaseUrl
83− -> ClientOptions -> EndpointResult t m api f tag
122+------------------------------------------------------------------------------
124+instance {-# OVERLAPPING #-}
86−instance {-# OVERLAPPING #-} (HasClientR t m (layoutLeft) f tag,
125+ (HasClientR t m (layoutLeft) f,
87− HasClientR t m (layoutRight) f tag
126+ HasClientR t m (layoutRight) f
88− ) => HasClientR t m (layoutLeft :<|> layoutRight) f tag where
127+ ) => HasClientR t m (layoutLeft :<|> layoutRight) f where
89− type ClientR t m (layoutLeft :<|> layoutRight) f tag =
128+ type ClientR t m (layoutLeft :<|> layoutRight) f =
90− ClientR t m (layoutLeft) f tag :<|> ClientR t m (layoutRight) f tag
129+ ClientR t m layoutLeft f :<|> ClientR t m layoutRight f
91− clientRWithRoute _ tP mP tagP _ url opts =
130+ clientRWithRoute _ tP mP _ url opts =
92− clientRWithRoute (Proxy @(layoutLeft)) tP mP tagP undefined url opts
131+ clientRWithRoute (Proxy @layoutLeft) tP mP undefined url opts
94− clientRWithRoute (Proxy @(layoutRight)) tP mP tagP undefined url opts
133+ clientRWithRoute (Proxy @layoutRight) tP mP undefined url opts
97−
135+#if MIN_VERSION_servant (0,13,0)
98−-- instance {-# OVERLAPPING #-} (HasClientR t m (Sealed layoutLeft) f tag,
137+instance HasClientR t m EmptyClient f where
99−-- HasClientR t m (Sealed layoutRight) f tag
138+ type ClientR t m api f = EmptyClient
100−-- ) => HasClientR t m (Sealed layoutLeft :<|> Sealed layoutRight) f tag where
101−-- type ClientR t m (Sealed layoutLeft :<|> Sealed layoutRight) f tag =
102−-- ClientR t m (Sealed layoutLeft) f tag :<|> ClientR t m (Sealed layoutRight) f tag
103−-- clientRWithRoute _ tP mP tagP _ url opts =
139+ clientRWithRoute _ _ _ _ _ _ = EmptyClient
104−-- clientRWithRoute (Proxy @(Sealed layoutLeft)) tP mP tagP undefined url opts
140+#endif
106−-- clientRWithRoute (Proxy @(Sealed layoutRight)) tP mP tagP undefined url opts
109class ToTuple xs where
143class ToTuple xs where
@@ -111,194 +145,304 @@ class ToTuple xs where
111 toTuple :: xs -> Tuple xs
145 toTuple :: xs -> Tuple xs
112 fromTuple :: Tuple xs -> xs
146 fromTuple :: Tuple xs -> xs
114−-- class FromTuple xs where
115−-- type UnTuple xs :: *
116−-- fromTuple :: Tuple xs -> xs
118data Sealed a
148data Sealed a
120type family Seal a where
151type family Seal a where
121 Seal (a :<|> b) = Seal a :<|> Seal b
152 Seal (a :<|> b) = Seal a :<|> Seal b
153+ Seal Raw = SealedRaw
122 Seal a = Sealed a
154 Seal a = Sealed a
124-- | Turn a single Endpoint into a client, by turning the input HList
157-- | Turn a single Endpoint into a client, by turning the input HList
125-- into a tuple
158-- into a tuple
126−instance {-# OVERLAPPING #-} forall t m layout f tag .(EndpointR t m layout f tag,
159+instance {-# OVERLAPPING #-} forall t m layout f .(EndpointR t m layout f,
127− ToTuple (HList (EInputs t m layout f tag)),
160+ ToTuple (HList (EInputs t m layout f)),
129 , Traversable f
162 , Traversable f
130 , SupportsServantReflex t m
163 , SupportsServantReflex t m
131− ) => HasClientR t (m :: * -> *) (Sealed layout) (f :: * -> *) tag where
164+ ) => HasClientR t (m :: * -> *) (Sealed layout) (f :: * -> *) where
132− type ClientR t m (Sealed layout) f tag =
165+ type ClientR t m (Sealed layout) f =
133− Event t (f (Tuple (HList (EInputs t m layout f tag))))
166+ Event t (f (Tuple (HList (EInputs t m layout f))))
134− -> m (Event t (f (EOutput t m layout f tag)))
167+ -> m (Event t (f (EOutput t m layout f)))
135− clientRWithRoute _ mP fP tagP dReq url opts (reqs :: Event t (f (Tuple (HList (EInputs t m layout f tag))))) = do
168+ clientRWithRoute _ mP fP dReq url opts (reqs :: Event t (f (Tuple (HList (EInputs t m layout f ))))) = do
136− let reqTuples = fmap (fromTuple @(HList (EInputs t m layout f tag))) <$> reqs
169+ let reqTuples = fmap (fromTuple @(HList (EInputs t m layout f ))) <$> reqs
171+ -- TODO: replace these 2 lines w/ the next 2. The trace is for library debugging
172+ reqRs = traceEventWith (concat . fmap ((<> "\n") . show)) $ fmap (mkReq @t @m @layout @f) <$> reqTuples
173+ reqs' = ffor (attachPromptlyDyn url reqRs) $ \(bUrl, rs) -> mkXhrRequest bUrl <$> rs
137− reqs' = ffor (attachPromptlyDyn url reqTuples) $ \(bUrl, inputs) ->
174+ -- reqs' = ffor (attachPromptlyDyn url reqTuples) $ \(bUrl, inputs) ->
138− mkXhrRequest bUrl . mkReq @t @m @layout @f @tag <$> inputs
175+ -- mkXhrRequest bUrl . mkReq @t @m @layout @f <$> inputs
139− resps <- performRequestsAsync reqs'
176+ resps <- performRequestsAsync $ reqs'
140− return (fmap (getResp @t @m @layout @f @tag) <$> resps)
177+ return (fmap (getResp @t @m @layout @f) <$> resps)
143−instance (SupportsServantReflex t m, Traversable f) => HasClientR t m Raw f tag where
180+instance (SupportsServantReflex t m, Traversable f) => HasClientR t m SealedRaw f where
144− type ClientR t m Raw f tag = Event t (f (XhrRequest T.Text)) -> m (Event t (f XhrResponse))
181+ type ClientR t m SealedRaw f = Event t (f (XhrRequest T.Text)) -> m (Event t (f XhrResponse))
145− clientRWithRoute _ mP fP tagP dReq url opts reqs = performRequestsAsync reqs
182+ clientRWithRoute _ mP fP dReq url opts reqs = performRequestsAsync reqs
148−instance (MimeUnrender ct a, ReflectMethod method, cts' ~ (ct ': cts), SupportsServantReflex t m, Applicative f
185+instance {-# OVERLAPPING #-}(MimeUnrender ct a, ReflectMethod method, cts' ~ (ct ': cts), SupportsServantReflex t m, Applicative f
149− ) => EndpointR t m (Verb method status cts' a) f (tag :: *) where
186+ ) => EndpointR t m (Verb method status cts' a) f where
150− type EndpointResult t m (Verb method status cts' a) f tag = Event t tag -> m (Event t (ReqResult tag a))
151− type EInputs t m (Verb method status cts' a) f tag = '[]
187+ type EInputs t m (Verb method status cts' a) f = '[]
152− type EOutput t m (Verb method status cts' a) f tag = Either String a
188+ type EOutput t m (Verb method status cts' a) f = Either String a
155− clientEndpoint _ _ _ _ _ _ _ = undefined
156 mkReq _ = emptyReqR . E.decodeUtf8 $ reflectMethod (Proxy @method)
190 mkReq _ = emptyReqR . E.decodeUtf8 $ reflectMethod (Proxy @method)
157 getResp resp = case _xhrResponse_response resp of
191 getResp resp = case _xhrResponse_response resp of
158 Just (XhrResponseBody_ArrayBuffer x) -> mimeUnrender (Proxy @ct) (BL.fromStrict x)
192 Just (XhrResponseBody_ArrayBuffer x) -> mimeUnrender (Proxy @ct) (BL.fromStrict x)
160−-- type ClientFunction t m f tag ein eout = Event t (f (tag, Tuple (HList ein))) -> m (Event t (f (tag, eout)))
194+instance {-# OVERLAPPING #-}(ReflectMethod method, SupportsServantReflex t m, Applicative f
195+ ) => EndpointR t m (Verb method status cts' NoContent) f where
196+ type EInputs t m (Verb method status cts' NoContent) f = '[]
197+ type EOutput t m (Verb method status cts' NoContent) f = Either String NoContent
199+ mkReq _ = emptyReqR . E.decodeUtf8 $ reflectMethod (Proxy @method)
200+ getResp resp = Right NoContent -- TODO: Should EOutput be `NoContent` rather than Either... ?
203+instance {-# OVERLAPPING #-}
206+ ReflectMethod method, cts' ~ (ct ': cts),
207+ SupportsServantReflex t m,
209+ BuildHeaderKeysTo hs
210+ ) => EndpointR t m (Verb method status cts' (Headers hs a)) f where
211+ type EInputs t m (Verb method status cts' (Headers hs a)) f = '[]
212+ type EOutput t m (Verb method status cts' (Headers hs a)) f = Either String (Headers hs a)
214+ mkReq _ = set (field @"reqRRespHeaders") (OnlyHeaders (Set.fromList (buildHeaderKeysTo (Proxy @hs)))) $ emptyReqR $ E.decodeUtf8 $ reflectMethod (Proxy @method)
215+ getResp resp = case _xhrResponse_response resp of
216+ Just (XhrResponseBody_ArrayBuffer x) ->
217+ let hs = buildHeadersTo
218+ . fmap (first (mk . E.encodeUtf8) . second E.encodeUtf8)
220+ $ _xhrResponse_headers resp
221+ in fmap (flip Headers (hs)) $ mimeUnrender (Proxy @ct) (BL.fromStrict x)
224+instance {-# OVERLAPPING #-}(MimeUnrender ct a,
226+ BuildHeaderKeysTo hs,
227+ ReflectMethod method,
228+ SupportsServantReflex t m,
230+ ) => EndpointR t m (Verb method status cts' (Headers hs NoContent)) f where
231+ type EInputs t m (Verb method status cts' (Headers hs NoContent)) f = '[]
232+ type EOutput t m (Verb method status cts' (Headers hs NoContent)) f = Either String (Headers hs NoContent)
234+ mkReq _ = set (field @"reqRRespHeaders") (OnlyHeaders (Set.fromList (buildHeaderKeysTo (Proxy @hs)))) $ emptyReqR . E.decodeUtf8 $ reflectMethod (Proxy @method)
235+ getResp resp = case _xhrResponse_response resp of
236+ Just (XhrResponseBody_ArrayBuffer x) ->
237+ let hs = buildHeadersTo
238+ . fmap (first (mk . E.encodeUtf8) . second E.encodeUtf8)
240+ $ _xhrResponse_headers resp
241+ in Right (Headers NoContent hs)
162instance (SupportsServantReflex t m,
244instance (SupportsServantReflex t m,
163 ToHttpApiData a,
245 ToHttpApiData a,
164− EndpointR t m sublayout f tag,
246+ EndpointR t m sublayout f,
165 Applicative f
247 Applicative f
166− ) => EndpointR t m (Capture capture a :> sublayout) f (tag :: *) where
248+ ) => EndpointR t m (Capture capture a :> sublayout) f where
250+ type EInputs t m (Capture capture a :> sublayout) f = a ': EInputs t m sublayout f
251+ type EOutput t m (Capture capture a :> sublayout) f = EOutput t m sublayout f
253+ mkReq (HCons x xs) = (\a -> over (field @"reqRPathParts") (toUrlPiece a:)) x $
254+ mkReq @t @m @sublayout @f xs
168− type EndpointResult t m (Capture capture a :> sublayout) f tag =
170− EndpointResult t m sublayout f tag
256+ getResp = getResp @t @m @sublayout @f
172− type EInputs t m (Capture capture a :> sublayout) f tag = a ': EInputs t m sublayout f tag
258+instance (SupportsServantReflex t m,
173− type EOutput t m (Capture capture a :> sublayout) f tag = EOutput t m sublayout f tag
259+ ToHttpApiData a,
174− eInputs = undefined
260+ EndpointR t m sublayout f,
175− clientEndpoint _ pM pF pTag reqs url opts vals =
261+ Applicative f
176− clientEndpoint (Proxy :: Proxy sublayout) pM pF pTag reqs' url opts
262+ ) => EndpointR t m (CaptureAll capture a :> sublayout) f where
177− where reqs' = (\v -> over (field @"reqRPathParts") (toUrlPiece v :))
180− mkReq (HCons x xs) = (\a -> over (field @"reqRPathParts") (toUrlPiece a:)) x $ mkReq @t @m @sublayout @f @tag xs
264+ type EInputs t m (CaptureAll capture a :> sublayout) f = [a] ': EInputs t m sublayout f
265+ type EOutput t m (CaptureAll capture a :> sublayout) f = EOutput t m sublayout f
267+ mkReq (HCons x xs) = (\a -> over (field @"reqRPathParts") (fmap toUrlPiece a <>)) x $
268+ mkReq @t @m @sublayout @f xs
182− getResp = getResp @t @m @sublayout @f @tag
270+ getResp = getResp @t @m @sublayout @f
185instance (SupportsServantReflex t m,
273instance (SupportsServantReflex t m,
186 KnownSymbol sym,
274 KnownSymbol sym,
187− EndpointR t m sublayout f tag,
275+ EndpointR t m sublayout f,
188 Applicative f
276 Applicative f
189− ) => EndpointR t m (sym :> sublayout) f (tag :: *) where
277+ ) => EndpointR t m (sym :> sublayout) f where
279+ type EInputs t m (sym :> sublayout) f = EInputs t m sublayout f
280+ type EOutput t m (sym :> sublayout) f = EOutput t m sublayout f
191− type EndpointResult t m (sym :> sublayout) f tag =
282+ mkReq r = over (field @"reqRPathParts") (T.pack (symbolVal (Proxy @sym)) :) $ mkReq @t @m @sublayout @f r
192− EndpointResult t m sublayout f tag
194− type EInputs t m (sym :> sublayout) f tag = EInputs t m sublayout f tag
284+ getResp = getResp @t @m @sublayout @f
195− type EOutput t m (sym :> sublayout) f tag = EOutput t m sublayout f tag
196− clientEndpoint _ pM pF pTag reqs url opts =
197− clientEndpoint (Proxy :: Proxy sublayout) pM pF pTag reqs' url opts
198− where reqs' = (over (field @"reqRPathParts") (T.pack (symbolVal (Proxy @sym)) :))
200− mkReq r = over (field @"reqRPathParts") (T.pack (symbolVal (Proxy @sym)) :) $ mkReq @t @m @sublayout @f @tag r
202− getResp = getResp @t @m @sublayout @f @tag
203instance (SupportsServantReflex t m,
286instance (SupportsServantReflex t m,
204 ToHttpApiData a,
287 ToHttpApiData a,
205− EndpointR t m sublayout f tag,
288+ EndpointR t m sublayout f,
206 KnownSymbol sym,
289 KnownSymbol sym,
207 Applicative f
290 Applicative f
208− ) => EndpointR t m (QueryParam sym a :> sublayout) f (tag :: *) where
291+ ) => EndpointR t m (QueryParam sym a :> sublayout) f where
210− type EndpointResult t m (QueryParam sym a :> sublayout) f tag =
212− EndpointResult t m sublayout f tag
214− type EInputs t m (QueryParam sym a :> sublayout) f tag = Maybe a ': EInputs t m sublayout f tag
293+ type EInputs t m (QueryParam sym a :> sublayout) f = Maybe a ': EInputs t m sublayout f
215− type EOutput t m (QueryParam sym a :> sublayout) f tag = EOutput t m sublayout f tag
294+ type EOutput t m (QueryParam sym a :> sublayout) f = EOutput t m sublayout f
216− clientEndpoint _ pM pF pTag reqs url opts vals = undefined -- TODO
295+
217− -- clientEndpoint (Proxy :: Proxy sublayout) pM pF pTag reqs' url opts
218− -- where reqs' = (\v -> over (field @"reqRPathParts") (toUrlPiece v :))
221 mkReq (HCons x xs) = over (field @"reqRParams") ((T.pack $ symbolVal (Proxy @sym),
296 mkReq (HCons x xs) = over (field @"reqRParams") ((T.pack $ symbolVal (Proxy @sym),
222 QueryPartParam $ fmap (toQueryParam) x) : ) $
297 QueryPartParam $ fmap (toQueryParam) x) : ) $
223− mkReq @t @m @sublayout @f @tag xs
298+ mkReq @t @m @sublayout @f xs
226− getResp = getResp @t @m @sublayout @f @tag
301+ getResp = getResp @t @m @sublayout @f
228instance (SupportsServantReflex t m,
303instance (SupportsServantReflex t m,
229 ToHttpApiData a,
304 ToHttpApiData a,
230− EndpointR t m sublayout f tag,
305+ EndpointR t m sublayout f,
231 KnownSymbol sym,
306 KnownSymbol sym,
232 Applicative f
307 Applicative f
233− ) => EndpointR t m (QueryParams sym a :> sublayout) f (tag :: *) where
308+ ) => EndpointR t m (QueryParams sym a :> sublayout) f where
235− type EndpointResult t m (QueryParams sym a :> sublayout) f tag =
310+ type EInputs t m (QueryParams sym a :> sublayout) f = [a] ': EInputs t m sublayout f
236− f a ->
311+ type EOutput t m (QueryParams sym a :> sublayout) f = EOutput t m sublayout f
237− EndpointResult t m sublayout f tag
239− type EInputs t m (QueryParams sym a :> sublayout) f tag = [a] ': EInputs t m sublayout f tag
240− type EOutput t m (QueryParams sym a :> sublayout) f tag = EOutput t m sublayout f tag
242− clientEndpoint _ pM pF pTag reqs url opts vals = undefined -- TODO
243 mkReq (HCons x xs) =
313 mkReq (HCons x xs) =
244 let newParams = (T.pack (symbolVal (Proxy @sym)), QueryPartParams (toQueryParam <$> x))
314 let newParams = (T.pack (symbolVal (Proxy @sym)), QueryPartParams (toQueryParam <$> x))
245− in over (field @"reqRParams") (newParams :) $ mkReq @t @m @sublayout @f @tag xs
315+ in over (field @"reqRParams") (newParams :) $ mkReq @t @m @sublayout @f xs
247− getResp = getResp @t @m @sublayout @f @tag
317+ getResp = getResp @t @m @sublayout @f
249instance (SupportsServantReflex t m,
319instance (SupportsServantReflex t m,
250− EndpointR t m sublayout f tag,
320+ EndpointR t m sublayout f,
251 KnownSymbol sym,
321 KnownSymbol sym,
252 Applicative f
322 Applicative f
253− ) => EndpointR t m (QueryFlag sym :> sublayout) f (tag :: *) where
323+ ) => EndpointR t m (QueryFlag sym :> sublayout) f where
255− type EndpointResult t m (QueryFlag sym :> sublayout) f tag =
257− EndpointResult t m sublayout f tag
259− type EInputs t m (QueryFlag sym :> sublayout) f tag = Bool ': EInputs t m sublayout f tag
325+ type EInputs t m (QueryFlag sym :> sublayout) f = Bool ': EInputs t m sublayout f
260− type EOutput t m (QueryFlag sym :> sublayout) f tag = EOutput t m sublayout f tag
326+ type EOutput t m (QueryFlag sym :> sublayout) f = EOutput t m sublayout f
262 mkReq (HCons x xs) =
328 mkReq (HCons x xs) =
263 let newParam = (T.pack (symbolVal (Proxy @sym)), QueryPartFlag x)
329 let newParam = (T.pack (symbolVal (Proxy @sym)), QueryPartFlag x)
264− in over (field @"reqRParams") (newParam :) $ mkReq @t @m @sublayout @f @tag xs
330+ in over (field @"reqRParams") (newParam :) $ mkReq @t @m @sublayout @f xs
266− getResp = getResp @t @m @sublayout @f @tag
332+ getResp = getResp @t @m @sublayout @f
268instance (SupportsServantReflex t m,
334instance (SupportsServantReflex t m,
269− EndpointR t m sublayout f tag,
335+ EndpointR t m sublayout f,
270 MimeRender ct a,
336 MimeRender ct a,
271 Applicative f
337 Applicative f
272− ) => EndpointR t m (ReqBody (ct ': cts) a :> sublayout) f (tag :: *) where
338+ ) => EndpointR t m (ReqBody (ct ': cts) a :> sublayout) f where
274− type EndpointResult t m ( ReqBody (ct ': cts) a :> sublayout) f tag =
276− EndpointResult t m sublayout f tag
278− type EInputs t m (ReqBody (ct ': cts) a :> sublayout) f tag = a ': EInputs t m sublayout f tag
341+ type EInputs t m (ReqBody (ct ': cts) a :> sublayout) f = a ': EInputs t m sublayout f
279− type EOutput t m (ReqBody (ct ': cts) a :> sublayout) f tag = EOutput t m sublayout f tag
342+ type EOutput t m (ReqBody (ct ': cts) a :> sublayout) f = EOutput t m sublayout f
281 mkReq (HCons x xs) =
344 mkReq (HCons x xs) =
282− set (field @"reqRBody") (Just (mimeRender (Proxy @ct) x, T.pack (show (contentType (Proxy @ct))))) $ mkReq @t @m @sublayout @f @tag xs
345+ set (field @"reqRBody") (Just (mimeRender (Proxy @ct) x, T.pack (show (contentType (Proxy @ct))))) $ mkReq @t @m @sublayout @f xs
347+ getResp = getResp @t @m @sublayout @f
284− getResp = getResp @t @m @sublayout @f @tag
286instance (SupportsServantReflex t m,
350instance (SupportsServantReflex t m,
287− EndpointR t m sublayout f tag,
351+ EndpointR t m sublayout f,
288 Applicative f
354 Applicative f
289− ) => EndpointR t m (BasicAuth realm usr :> sublayout) f (tag :: *) where
355+ ) => EndpointR t m (Header sym a :> sublayout) f where
291− type EndpointResult t m ( BasicAuth realm usr :> sublayout) f tag =
293− EndpointResult t m sublayout f tag
295− type EInputs t m (BasicAuth realm usr :> sublayout) f tag = BasicAuthData ': EInputs t m sublayout f tag
358+ type EInputs t m (Header sym a :> sublayout) f = a ': EInputs t m sublayout f
296− type EOutput t m (BasicAuth realm usr :> sublayout) f tag = EOutput t m sublayout f tag
359+ type EOutput t m (Header sym a :> sublayout) f = EOutput t m sublayout f
298 mkReq (HCons x xs) =
361 mkReq (HCons x xs) =
362+ over (field @"reqRHeaders")
363+ -- ((symbolVal (Proxy @sym), (mimeRender (Proxy @a) x)) :)
364+ ((T.pack $ symbolVal (Proxy @sym), E.decodeUtf8 $ toHeader x) :)
299− set (field @"reqRAuthData") (Just x) $ mkReq @t @m @sublayout @f @tag xs
365+ $ mkReq @t @m @sublayout @f xs
367+ getResp = getResp @t @m @sublayout @f
369+#if MIN_VERSION_servant(0,13,0)
371+instance (SupportsServantReflex t m,
372+ EndpointR t m sublayout f,
376+ ) => EndpointR t m (Summary desc :> sublayout) f where
378+ type EInputs t m (Summary desc :> sublayout) f = EInputs t m sublayout f
379+ type EOutput t m (Summary desc :> sublayout) f = EOutput t m sublayout f
381+ mkReq = mkReq @t @m @sublayout @f
301− getResp = getResp @t @m @sublayout @f @tag
383+ getResp = getResp @t @m @sublayout @f
387+#if MIN_VERSION_servant(0,13,0)
389+instance (SupportsServantReflex t m,
390+ EndpointR t m sublayout f,
394+ ) => EndpointR t m (Description desc :> sublayout) f where
396+ type EInputs t m (Descriptiok desc :> sublayout) f = EInputs t m sublayout f
397+ type EOutput t m (Description desc :> sublayout) f = EOutput t m sublayout f
399+ mkReq = mkReq @t @m @sublayout @f
401+ getResp = getResp @t @m @sublayout @f
404+instance (SupportsServantReflex t m,
405+ EndpointR t m sublayout f,
409+ ) => EndpointR t m (IsSecure :> sublayout) f where
412+ type EInputs t m (IsSecure :> sublayout) f = EInputs t m sublayout f
413+ type EOutput t m (IsSecure :> sublayout) f = EOutput t m sublayout f
415+ mkReq = mkReq @t @m @sublayout @f
417+ getResp = getResp @t @m @sublayout @f
419+instance (SupportsServantReflex t m,
420+ EndpointR t m sublayout f,
424+ ) => EndpointR t m (Vault :> sublayout) f where
427+ type EInputs t m (Vault :> sublayout) f = EInputs t m sublayout f
428+ type EOutput t m (Vault :> sublayout) f = EOutput t m sublayout f
430+ mkReq = mkReq @t @m @sublayout @f
432+ getResp = getResp @t @m @sublayout @f
434+instance (SupportsServantReflex t m,
435+ EndpointR t m sublayout f,
437+ ) => EndpointR t m (BasicAuth realm usr :> sublayout) f where
439+ type EInputs t m (BasicAuth realm usr :> sublayout) f = BasicAuthData ': EInputs t m sublayout f
440+ type EOutput t m (BasicAuth realm usr :> sublayout) f = EOutput t m sublayout f
442+ mkReq (HCons x xs) =
443+ set (field @"reqRAuthData") (Just x) $ mkReq @t @m @sublayout @f xs
445+ getResp = getResp @t @m @sublayout @f
304instance ToTuple (HList '[]) where
448instance ToTuple (HList '[]) where
@@ -321,18 +465,25 @@ instance ToTuple (HList '[a,b,c]) where
321 toTuple (HCons a (HCons b (HCons c HNil))) = (a,b,c)
465 toTuple (HCons a (HCons b (HCons c HNil))) = (a,b,c)
322 fromTuple (a,b,c) = HCons a (HCons b (HCons c HNil))
466 fromTuple (a,b,c) = HCons a (HCons b (HCons c HNil))
324−type MyAPI = Capture "hello" Int :> Capture "hello2" Bool :> Get '[JSON] Int
468+type MyAPI = Header "hi" Int :> Capture "hello" Int :> Capture "hello2" Bool :> Get '[JSON] (Headers '[Header "hi" Int] Int)
325 :<|> Get '[JSON] Bool
469 :<|> Get '[JSON] Bool
328m :: forall t m.MonadWidget t m => m ()
474m :: forall t m.MonadWidget t m => m ()
330− let (a :<|> b) = clientR (Proxy @(MyAPI)) (Proxy :: Proxy m) (Proxy :: Proxy t)
476+ let (a :<|> b) = clientR (Proxy @MyAPI) (Proxy :: Proxy m) (Proxy :: Proxy t)
331− (Proxy @[]) (Proxy @Integer) undefined
477+ (Proxy @[]) undefined
332 btn <- button "Hello"
478 btn <- button "Hello"
333− resA <- a (fmap (:[]) ((5,True) <$ btn))
479+ resA <- a (fmap (:[]) ((2, 5,True) <$ btn))
334 resB <- b (fmap (:[]) (() <$ btn))
480 resB <- b (fmap (:[]) (() <$ btn))
335− display =<< holdDyn "waiting" (leftmost [show <$> resA, show <$> resB])
481+ display =<< holdDyn "waiting" (leftmost [show <$> resB ])
486+ let rawR = clientR (Proxy @MyAPI2) (Proxy @m) (Proxy @t) (Proxy @[]) undefined
336 return ()
487 return ()
338data ReqR = ReqR
489data ReqR = ReqR
@@ -345,12 +496,25 @@ data ReqR = ReqR
345 , reqRAuthData :: Maybe BasicAuthData
496 , reqRAuthData :: Maybe BasicAuthData
346 } deriving (Generic)
497 } deriving (Generic)
499+instance Show ReqR where
500+ show (ReqR m pp ps b hs hs' a) = concat $ L.intersperse "\n" [
502+ , ("reqRMethod = " <> show m)
503+ , ("reqRPathParts = " <> show pp)
504+ , ("reqRParams = " <> show ps)
505+ , ("reqRBody = " <> show b)
506+ , ("reqRHeaders = " <> show hs)
507+ , ("reqRRespHeaders = " <> show hs')
508+ , ("reqRAuthData = " <> maybe "Nothing" (const "Just <<redacted>>") a)
348emptyReqR :: T.Text -> ReqR
511emptyReqR :: T.Text -> ReqR
349emptyReqR method = ReqR method [] [] Nothing [] (OnlyHeaders mempty) Nothing
512emptyReqR method = ReqR method [] [] Nothing [] (OnlyHeaders mempty) Nothing
351data QueryPart = QueryPartParam (Maybe Text)
514data QueryPart = QueryPartParam (Maybe Text)
352 | QueryPartParams [Text]
515 | QueryPartParams [Text]
353 | QueryPartFlag Bool
516 | QueryPartFlag Bool
355mkXhrRequest :: BaseUrl -> ReqR -> XhrRequest T.Text
519mkXhrRequest :: BaseUrl -> ReqR -> XhrRequest T.Text
356mkXhrRequest reqHost req =
520mkXhrRequest reqHost req =
@@ -376,15 +540,28 @@ mkXhrRequest reqHost req =
376 queryString = T.intercalate "&" . catMaybes . map queryPartString $ reqRParams req
540 queryString = T.intercalate "&" . catMaybes . map queryPartString $ reqRParams req
377 url = showBaseUrl reqHost </> path <> if T.null queryString then "" else (T.cons '?' queryString)
541 url = showBaseUrl reqHost </> path <> if T.null queryString then "" else (T.cons '?' queryString)
379− xhrHeaders = [] -- TODO
543+ (headers, body) =
544+ let headers0 = M.fromList $ reqRHeaders req
545+ in case reqRBody req of
546+ Nothing -> (headers0, "")
547+ Just (rb,ct) -> (M.insert "Content-Type" ct headers0,
548+ E.decodeUtf8 $ BL.toStrict rb)
381 xhrReqConfig = def
550 xhrReqConfig = def
382− { _xhrRequestConfig_headers = M.fromList xhrHeaders
551+ { _xhrRequestConfig_headers = headers
383 , _xhrRequestConfig_user = E.decodeUtf8 . basicAuthUsername <$> reqRAuthData req
552 , _xhrRequestConfig_user = E.decodeUtf8 . basicAuthUsername <$> reqRAuthData req
384 , _xhrRequestConfig_password = E.decodeUtf8 . basicAuthPassword <$> reqRAuthData req
553 , _xhrRequestConfig_password = E.decodeUtf8 . basicAuthPassword <$> reqRAuthData req
385 , _xhrRequestConfig_responseType = Just XhrResponseType_ArrayBuffer
554 , _xhrRequestConfig_responseType = Just XhrResponseType_ArrayBuffer
386− , _xhrRequestConfig_sendData = "" -- TODO
555+ , _xhrRequestConfig_sendData = body
556+ , _xhrRequestConfig_responseHeaders = reqRRespHeaders req
387 , _xhrRequestConfig_withCredentials = False
557 , _xhrRequestConfig_withCredentials = False
389 xhrReq = XhrRequest (reqRMethod req) url xhrReqConfig
559 xhrReq = XhrRequest (reqRMethod req) url xhrReqConfig
390 in xhrReq
560 in xhrReq
562+transformExample :: MonadWidget t m => ((Int, Char) -> Performable m Bool) -> Event t (Int, Char) -> m (Event t Bool)
563+transformExample f = \triggers -> performEvent (f <$> triggers)
564+-- transformExample = undefined -- let x = performEvent :: _ in undefined
566+transform :: MonadWidget t m => forall a. (inp -> IO outp) -> (Event t inp -> m (Event t outp))
567+transform = undefined