git.iko.soy/typeable/servant-reflex
on master help sign in
Fix up readme type errors
commitfcf908e65dfb3563bf3ba5c5453fc2f6f55fc8ca authorGreg Hale <imalsogreg@gmail.com> dateMon 12 Dec 2016, 14:11 (10 years ago) parent00704c3
4 files changed+25−16
README.md+11−13 overrides-ghc.nix−1 overrides.nix−1 src/Servant/Common/Req.hs+14−1
README.md+11−13
@@ -15,16 +15,16 @@ We have a webservice API defined in a module where both the server (compiled wit
1515
1616```haskell
1717type API = "getint" :> Get '[JSON] Int
18− :<|> "sayhi" :> QueryParam "username" String
19− :> QueryParams "greetings" String
18+ :<|> "sayhi" :> QueryParam "username" Text
19+ :> QueryParams "greetings" Text
2020 :> QueryFlag "gusto"
21− :> Get '[JSON] String
21+ :> Get '[JSON] Text
2222 :<|> "double" :> ReqBody '[JSON] Double
2323 :> Post '[JSON] Double
2424 :<|> Raw
2525```
2626
27−`servant-reflex` then computes functions that can query the API through an `XhrRequest`.
27+`servant-reflex` then computes client functions that can query the API through an `XhrRequest`.
2828
2929```haskell
3030
@@ -36,7 +36,7 @@ type API = "getint" :> Get '[JSON] Int
3636 (constDyn (BasePath "/"))
3737```
3838
39−These client functions are computed from the API and manage serialization, XhrRequest generation, and deserialization for you. `a` parameters become `Dynamic t (Either String a)` values. You provide a trigger event and receive an `Event t (ReqResult a)`, with responses from the API server (which you would write with `servant-server`).
39+These client functions are computed from your API type. They manage serialization, XhrRequest generation, and deserialization for you. `a` parameters used in URL captures become `Dynamic t (Either Text a)` parameters in the client functions. 'QueryFlag', 'QueryParams' and 'QueryParam' API parameters map to 'Dynamic t Bool', 'Dynamic t [a]' and 'Dynamic t (QParam a)' respectively. These parameters to the client function are wrapped with failure possibility to allow you to indicate at any time whether input validation for that parameter has failed and no valid XHR request can be generated. The final parameter is a trigger event for the XHR request. The return value `Event t (ReqResult a)` contains responses from the API server.
4040
4141```haskell
4242 -- No need to write these functions. servant-reflex creates them for you!
@@ -45,24 +45,22 @@ These client functions are computed from the API and manage serialization, XhrRe
4545 -> m (Event t (ReqResult Int)) -- ^ Consume the answer
4646
4747 sayhi :: MonadWidget t m
48− => Dynamic t (Either String String)
49− -- ^ One input parameter - the 'name'
50− -> Dynamic t [String]
48+ => Dynamic t (QParam Text)
49+ -- ^ One input parameter - the 'name', wrapped in 'QParam'
50+ -> Dynamic t [Text]
5151 -- ^ Another input: list of preferred greetings
5252 -> Dynamic t Bool
5353 -- ^ Flag for capitalizing the response
5454 -> Event t ()
5555 -- ^ Trigger the XHR Request
56− -> m (Event t (ReqResult String))
56+ -> m (Event t (ReqResult Text))
5757
5858 doubleit :: MonadWidget t m
59− => Dynamic t (Either String Double)
59+ => Dynamic t (Either Text Double)
6060 -> Event t ()
6161 -> m (Event t (ReqResult Double))
6262```
6363
64−Plug any of these functions into your reflex frontend to consume backend servant services. *Isomorphic!*
65−
6664`ReqResult a` is defined in [`Servant.Common.Req`](https://github.com/imalsogreg/servant-reflex/blob/6d866e338edb9bf6fd8f8d5083ff0187b4d8c0d2/src/Servant/Common/Req.hs#L40-L42) and reports whether or not your request was sent (if validation fails, the request won't be sent), and how decoding of the response went. You can pattern match on these explicitly, but usually you'll want to use `fmapMaybe :: (a -> Maybe b) -> Event t a -> Event t b` and one of the elimination functions to filter the result type you care about, like this:
6765
6866```haskell
@@ -90,7 +88,7 @@ This example builds some input fields to enter API parameters, buttons to trigge
9088 display =<< holdDyn (Just 0) serverInts
9189
9290 elClass "div" "hello-demo" $ do
93− nameText <- value <$> textInput def
91+ nameText <- QParamSome . value <$> textInput def
9492 greetings <- (fmap words . value) <$> textInput def
9593 withGusto <- checkbox def
9694 helloButton <- button "Say hi"
overrides-ghc.nix−1
@@ -1,7 +1,6 @@
11{ reflex-platform, ... }:
22let
33 pkgs = import <nixpkgs> {};
4− reflex-platform = import deps/reflex-platform {};
54 c2n = reflex-platform.cabal2nixResult;
65in reflex-platform.ghc.override {
76 overrides = self: super: {
overrides.nix−1
@@ -8,7 +8,6 @@ let
88in
99reflex-platform.ghcjs.override {
1010 overrides = self: super: {
11− reflex-dom = dontCheck (self.callPackage deps/reflex-dom {});
1211 servant = dontCheck (self.callPackage (cabal2nixResult deps/servant/servant) {});
1312 http-api-data = dontCheck (self.callPackage (cabal2nixResult deps/http-api-data) {});
1413 };
src/Servant/Common/Req.hs+14−1
@@ -51,7 +51,16 @@ response (ResponseFailure _ x) = Just x
5151response _ = Nothing
5252
5353
54−data QParam a = QParamSome a | QNone | QParamInvalid Text
54+-------------------------------------------------------------------------------
55+-- | You must wrap the parameter of a QueryParam endpoint with 'QParam' to
56+-- indicate whether the parameter is valid and present, validly absent, or
57+-- invalid
58+data QParam a = QParamSome a
59+ -- ^ A valid query parameter
60+ | QNone
61+ -- ^ Indication that the parameter is intentionally absent (the request is valid)
62+ | QParamInvalid Text
63+ -- ^ Indication that your validation failed (the request isn't valid)
5564
5665qParamToQueryPart :: ToHttpApiData a => QParam a -> Either Text (Maybe Text)
5766qParamToQueryPart (QParamSome a) = Right (Just $ toQueryParam a)
@@ -62,6 +71,10 @@ data QueryPart t = QueryPartParam (Dynamic t (Either Text (Maybe Text)))
6271 | QueryPartParams (Dynamic t [Text])
6372 | QueryPartFlag (Dynamic t Bool)
6473
74+
75+-------------------------------------------------------------------------------
76+-- The data structure used to build up request information while traversing
77+-- the shape of a servant API
6578data Req t = Req
6679 { reqMethod :: Text
6780 , reqPathParts :: [Dynamic t (Either Text Text)]