on text-jsstring help sign in
servant-reflex/exec/Example.hs
218 lines 7.9 kB history raw
1{-# LANGUAGE DataKinds #-}
2{-# LANGUAGE FlexibleContexts #-}
3{-# LANGUAGE GADTs #-}
4{-# LANGUAGE OverloadedStrings #-}
5{-# LANGUAGE RankNTypes #-}
6{-# LANGUAGE RecursiveDo #-}
7{-# LANGUAGE ScopedTypeVariables #-}
9module Main where
11------------------------------------------------------------------------------
12import Data.Bool
13import Data.Maybe
14import Control.Monad.Fix (MonadFix)
15import Data.Monoid (First(..), (<>))
16import Data.Text (Text)
17import qualified Data.Text as T
18import qualified Data.Text.Encoding as T
19import GHC.TypeLits
20import Servant.API
21import API
22import Data.Proxy
23import Text.Read (readMaybe)
24import Reflex.Dom.Core hiding (run)
25------------------------------------------------------------------------------
26import Servant.Reflex
27import Servant.Reflex.Multi
30api :: Proxy API
31api = Proxy
33main :: IO ()
34main = mainWidget $ do
35 divClass "example-base" run
36 divClass "example-multi" runMulti
39runMulti :: forall t m. (SupportsServantReflex t m,
40 DomBuilder t m,
41 DomBuilderSpace m ~ GhcjsDomSpace,
42 MonadFix m,
43 PostBuild t m,
44 MonadHold t m) => m ()
45runMulti = do
46 url <- baseUrlWidget
47 el "br" blank
48 let (_ :<|> _ :<|> sayHi :<|> dbl :<|> _ :<|> _ :<|> _ :<|> _ ) =
49 clientA api (Proxy :: Proxy m) (Proxy :: Proxy []) (Proxy :: Proxy Int) url
51 num :: Dynamic t (Either Text Double) <- fmap (note "No read" . readMaybe . T.unpack) . value <$> textInput def
52 num2 :: Dynamic t (Either Text Double) <- fmap (note "No read" . readMaybe . T.unpack) . value <$> textInput def
54 b <- button "Run dbl multi"
55 reqCount :: Dynamic t Int <- count b
56 r <- dbl ((\x y -> [x,y]) <$> num <*> num2) (tag (current reqCount) b)
57 dynText =<< holdDyn "Waiting" (T.pack . show . fmap reqSuccess <$> r)
59 lastInd <- holdDyn [] $ fmap reqTag <$> r
60 display lastInd
62 divClass "demo-group" $ do
63 nms <- fmap (fmap T.words . value) $ divClass "" $ do
64 text "Names"
65 textInput def
66 grts <- fmap (fmap T.words . value) $ divClass "" $ do
67 text "Greetings"
68 textInput def
69 gust <- fmap (value) $ divClass "gusto-input" $ checkbox False def
70 b <- button "Go"
71 r' <- sayHi (fmap QParamSome <$> nms) (fmap (:[]) $ grts)
72 (constDyn [True, False]) (1 <$ b)
74 dynText =<< holdDyn "Waiting" (T.pack . show . catMaybes .
75 fmap reqSuccess <$> r')
78 return ()
80run :: forall t m. (SupportsServantReflex t m,
81 DomBuilder t m,
82 DomBuilderSpace m ~ GhcjsDomSpace,
83 MonadFix m,
84 PostBuild t m,
85 MonadHold t m) => m ()
86run = mdo
88 reqCount <- count $ leftmost
89 [() <$ unitBtn, () <$ intBtn, () <$ sayHiClicks, () <$ dblBtn, () <$ mpGo]
90 -- Allow user to choose the url target for the request
91 -- (alternatively we could just `let url = constDyn (BasePath "/")`)
92 url <- baseUrlWidget
93 el "br" (return ())
94 dynText $ showBaseUrl <$> url
96 el "br" (return ())
98 -- Name the computed API client functions
99 let tweakRequest = ClientOptions $ \r -> do
100 return $ r & withCredentials .~ True
101 let (getUnit :<|> getInt :<|> sayhi :<|> dbl
102 :<|> multi :<|> qna :<|> secret :<|> doRaw) =
103 clientWithOpts api (Proxy :: Proxy m) (Proxy :: Proxy Int) url tweakRequest
105 c2 = client (Proxy :: Proxy ComprehensiveAPI) (Proxy :: Proxy m) (Proxy :: Proxy ()) url -- Just make sure this compiles for now
107 (unitBtn, intBtn) <- elClass "div" "demo-group" $ do
108 unitBtn <- divClass "unit-button" $ button "Get unit"
109 intBtn <- divClass "int-button" $ button "Get int"
111 unitResponse <- getUnit $ tag (current reqCount) unitBtn
112 intResponse :: Event t (ReqResult Int Int) <- getInt $ tag (current reqCount) intBtn
114 score <- foldDyn (+) 0 (fmapMaybe reqSuccess (intResponse))
116 r <- holdDyn "Waiting" $ fmap showXhrResponse $
117 leftmost [fmapMaybe response (unitResponse)
118 ,fmapMaybe response (intResponse)
119 ]
120 divClass "unit-int-response" $ el "p" $ dynText r >> el "br" (return ()) >> text "Total: " >> display score
121 return (unitBtn, intBtn)
123 sayHiClicks <- elClass "div" "demo-group" $ do
125 text "Name"
126 el "br" $ return ()
127 inp :: Dynamic t Text <- fmap value $ divClass "name-input" $ (textInput def)
128 let checkedName = fmap (\i -> bool (QParamSome i) (QParamInvalid "Need a name") (T.null i)) inp
129 el "br" $ return ()
131 text "Greetings (space-separated)"
132 el "br" $ return ()
133 greetings <- fmap (fmap T.words . value) $
134 divClass "greetings-input" $ (textInput def)
136 el "br" $ return ()
138 gusto <- fmap value $ divClass "gusto-input" $ checkbox False def
140 el "br" $ return ()
141 sayHiClicks :: Event t () <- divClass "hi-button" $ button "Say hi"
142 let triggers = leftmost [sayHiClicks, () <$ updated inp]
144 resp <- sayhi checkedName greetings gusto (tag (current reqCount) triggers)
145 divClass "greeting-response" $ dynText =<<
146 holdDyn "No hi yet" (leftmost [ fmapMaybe reqSuccess (resp)
147 , fmapMaybe reqFailure (resp)])
148 return sayHiClicks
150 dblBtn <- elClass "div" "demo-group" $ do
151 text "A Double to double"
152 el "br" $ return ()
153 dblinp <- fmap value $ divClass "double-input" $ textInput def
154 (dblBtn) <- divClass "double-button" $ button "Double it"
155 dblResp <- dbl (fmap (note "read failure" . readMaybe . T.unpack) $
156 dblinp) (tag (current reqCount) dblBtn)
157 divClass "double-errors" $ dynText =<<
158 holdDyn "(no errors)" (fmapMaybe reqFailure (dblResp))
159 el "br" (return ())
160 divClass "double-result" $ el "p" $ dynText =<<
161 holdDyn "No number yet" (fmap tShow $
162 fmapMaybe reqSuccess (dblResp))
163 return dblBtn
165 mpGo <- elClass "div" "demo-group" $ do
166 text "Multi-part path"
167 b <- value <$> checkbox False def
168 mpGo <- button "Test"
169 multiResp <- multi b (tag (current reqCount) mpGo)
170 dynText =<< holdDyn "No res yet" (fmap tShow $
171 fmapMaybe reqSuccess $
172 (multiResp))
173 return mpGo
175 return ()
177 el "br" $ return ()
179 elClass "div" "demo-group" $ do
180 text "JSON Unicode encoding test"
181 txt <- value <$> textInput def
182 ev <- fmap (1 <$) $ button "Question"
183 let dQ = Right . Question <$> traceDyn "will send: " txt
184 rr <- qna dQ ev
185 el "p" $
186 dynText =<< holdDyn "No Answer" (unAnswer <$> fmapMaybe reqSuccess rr)
188 divClass "demo-group" $ do
189 un <- fmap value $ text "Username" >> textArea def
190 pw <- fmap value $ text "Unhidden PW" >> textArea def
191 let ba :: Dynamic t (BasicAuthData ) = BasicAuthData
192 <$> fmap T.encodeUtf8 un
193 <*> fmap T.encodeUtf8 pw
194 b <- button "Get secret"
195 r <- secret (Just <$> ba) (0 <$ b)
196 res <- holdDyn Nothing (reqSuccess <$> r)
197 display res
200showXhrResponse :: XhrResponse -> Text
201showXhrResponse (XhrResponse stat stattxt rbmay rtmay respHeaders) =
202 T.unlines ["stat: " <> tShow stat
203 ,"stattxt: " <> tShow stattxt
204 ,"resp: " <> maybe "" showRB rbmay
205 ,"rtext: " <> tShow rtmay
206 ,"rHeaders: " <> tShow respHeaders]
208tShow :: Show a => a -> Text
209tShow = T.pack . show
211showRB :: XhrResponseBody -> Text
212showRB (XhrResponseBody_Default t) = tShow t
213showRB (XhrResponseBody_Text t) = tShow t
214showRB (XhrResponseBody_Blob t) = "<Blob>"
215showRB (XhrResponseBody_ArrayBuffer t) = tShow t
217note :: e -> Maybe a -> Either e a
218note e = maybe (Left e) Right