git.iko.soy/typeable/servant-reflex
on master help sign in
12 files changed+99−69
since splitsnapshots
unifiedsplit
.gitignore+2 .travis.yml+1 README.md+1−1 default.nix+9−17 exec/Example.hs+2−1 nix/reflex-platform.nix+2−2 servant-reflex.cabal+5−4 src/Servant/Common/BaseUrl.hs+5−1 src/Servant/Common/Req.hs+2−1 src/Servant/Reflex.hs+34−20 src/Servant/Reflex/Multi.hs+35−22 travis.nix+1
.gitignore+2
@@ -7,3 +7,5 @@ log
77*.stats
88out
99/.stack-work/
10+TAGS
11+dist-newstyle
.travis.yml+1
@@ -12,5 +12,6 @@ before_script:
1212
1313script:
1414 - nix-build travis.nix -A build
15+ - nix-build travis.nix -A buildGhc
1516 - nix-build travis.nix -A testserver
1617 - nix-build travis.nix -A testresults
README.md+1−1
@@ -7,7 +7,7 @@
77Keeping your frontend in sync with your API server can be difficult - when the
88API changes its input parameters or return type, XHR requests from the
99frontend will fail at runtime. If your API is defined by
10−[servant](haskell-servant.readthedocs.io) combinators, you can use
10+[servant](https://haskell-servant.readthedocs.io) combinators, you can use
1111`servant-reflex` to share the API between the server and frontend.
1212Syncronization between is checked at compile time, and rather than building XHR
1313requests by hand, API endpoints are available behind `reflex`'s FRP semantics.
default.nix+9−17
@@ -1,28 +1,20 @@
1−{ mkDerivation, aeson, base, bytestring, case-insensitive
2−, containers, data-default, exceptions, ghcjs-dom, http-api-data
3−, http-media, jsaddle, mtl, network-uri, reflex, reflex-dom-core
4−, safe, scientific, servant, servant-auth, stdenv
5−, string-conversions, text, transformers
1+{ mkDerivation, base, bytestring, case-insensitive, containers
2+, data-default, exceptions, ghcjs-dom, http-api-data, http-media
3+, jsaddle, mtl, network-uri, reflex, reflex-dom, reflex-dom-core
4+, safe, servant, servant-auth, stdenv, string-conversions, text
5+, transformers
66}:
77mkDerivation {
88 pname = "servant-reflex";
9− version = "0.3.5";
10− src = builtins.filterSource
11− (path: type:
12− baseNameOf path != "result"
13− && baseNameOf path != "nix"
14− ) ./.;
15− configureFlags = [ "-fexample" ];
9+ version = "0.3.6";
10+ src = ./.;
1611 isLibrary = true;
1712 isExecutable = true;
1813 libraryHaskellDepends = [
1914 base bytestring case-insensitive containers data-default exceptions
2015 ghcjs-dom http-api-data http-media jsaddle mtl network-uri reflex
21− reflex-dom-core safe servant servant-auth string-conversions text
22− transformers
23− ];
24− executableHaskellDepends = [
25− aeson base reflex reflex-dom-core scientific servant text
16+ reflex-dom reflex-dom-core safe servant servant-auth string-conversions
17+ text transformers
2618 ];
2719 description = "servant API generator for reflex apps";
2820 license = stdenv.lib.licenses.bsd3;
exec/Example.hs+2−1
@@ -21,7 +21,8 @@ import Servant.API
2121import API
2222import Data.Proxy
2323import Text.Read (readMaybe)
24−import Reflex.Dom.Core hiding (run)
24+import Reflex.Dom.Core hiding (run, mainWidget)
25+import Reflex.Dom (mainWidget)
2526------------------------------------------------------------------------------
2627import Servant.Reflex
2728import Servant.Reflex.Multi
nix/reflex-platform.nix+2−2
@@ -1,7 +1,7 @@
11let
2− rev = "df0bdcca5eb2a3236ec0496e4430d91876b29cf5";
2+ rev = "1aba6f367982bd6dd78ec2fda75ab246a62d32c5" ;
33in import (builtins.fetchTarball
44 {
55 url = "https://github.com/reflex-frp/reflex-platform/archive/${rev}.tar.gz";
6− sha256 = "1ja3vkq9px8f9iyiazq44mamaahgiphi9l236pvzbl5jvhi5c4qr";
6+ sha256 = "137vg6i8yy4lp6rz4wbvvhfcc9d9qf7j1b3fnng3r7sj63k7j664" ;
77 }) {}
servant-reflex.cabal+5−4
@@ -1,5 +1,5 @@
11Name: servant-reflex
2−Version: 0.3.5
2+Version: 0.3.6
33Synopsis: servant API generator for reflex apps
44Description: Generate reflex-compatible client functions from servant API descriptions
55License: BSD3
@@ -36,10 +36,10 @@ library
3636 jsaddle >= 0.8 && < 0.10,
3737 mtl >= 2.2.1 && < 2.3,
3838 network-uri >= 2.6 && < 2.7,
39− reflex >= 0.5 && < 0.8,
40− reflex-dom-core >= 0.6 && < 0.7,
39+ reflex >= 0.5 && < 0.9,
40+ reflex-dom-core >= 0.6 && < 0.8,
4141 safe >= 0.3.9 && < 0.4,
42− servant >= 0.16 && < 0.18,
42+ servant >= 0.16 && < 0.19,
4343 servant-auth >= 0.2.1 && < 0.4,
4444 string-conversions >= 0.4 && < 0.5,
4545 text >= 1.2 && < 1.3,
@@ -61,6 +61,7 @@ executable example
6161 base,
6262 scientific,
6363 servant,
64+ reflex-dom,
6465 reflex-dom-core,
6566 text
6667 default-language: Haskell2010
src/Servant/Common/BaseUrl.hs+5−1
@@ -1,4 +1,5 @@
11{-# LANGUAGE ConstraintKinds #-}
2+{-# LANGUAGE CPP #-}
23{-# LANGUAGE DeriveDataTypeable #-}
34{-# LANGUAGE DeriveGeneric #-}
45{-# LANGUAGE FlexibleContexts #-}
@@ -31,8 +32,11 @@ import Reflex
3132import Reflex.Dom.Core
3233import Text.Read
3334
34−
35+#if !MIN_VERSION_reflex_dom_core(0,7,0)
3536type SupportsServantReflex t m = (Reflex t, TriggerEvent t m, PerformEvent t m, HasWebView (Performable m), MonadJSM (Performable m))
37+#else
38+type SupportsServantReflex t m = (Reflex t, TriggerEvent t m, PerformEvent t m, MonadJSM (Performable m))
39+#endif
3640
3741-- | URI scheme to use
3842data Scheme =
src/Servant/Common/Req.hs+2−1
@@ -298,7 +298,9 @@ performRequests reqMeth rs reqHost opts trigger = do
298298performSomeRequestsAsync
299299 :: (MonadIO (Performable m),
300300 MonadJSM (Performable m),
301+#if !MIN_VERSION_reflex_dom_core(0,7,0)
301302 HasWebView (Performable m),
303+#endif
302304 PerformEvent t m,
303305 TriggerEvent t m,
304306 Traversable f,
@@ -428,4 +430,3 @@ builderToText = TE.decodeUtf8 . BL.toStrict . Builder.toLazyByteString
428430
429431escape :: T.Text -> T.Text
430432escape = T.pack . N.escapeURIString (not . N.isReserved) . T.unpack . TE.decodeUtf8 . BL.toStrict . Builder.toLazyByteString . toEncodedUrlPiece
431−
src/Servant/Reflex.hs+34−20
@@ -39,34 +39,36 @@ module Servant.Reflex
3939
4040------------------------------------------------------------------------------
4141import Control.Applicative
42−import Data.Monoid ((<>))
43−import qualified Data.Set as Set
44−import qualified Data.Text.Encoding as E
4542import qualified Data.CaseInsensitive as CI
4643import Data.Functor.Identity
47−import Data.Proxy (Proxy (..))
4844import qualified Data.Map as Map
45+import Data.Monoid ((<>))
46+import Data.Proxy (Proxy (..))
47+import qualified Data.Set as Set
4948import Data.Text (Text)
5049import qualified Data.Text as T
50+import qualified Data.Text.Encoding as E
5151import GHC.Exts (Constraint)
5252import GHC.TypeLits (KnownSymbol, symbolVal)
53−import Servant.API ((:<|>)(..),(:>), BasicAuth,
54− BasicAuthData, BuildHeadersTo(..),
55− Capture, contentType, Header,
56− Headers(..), HttpVersion, IsSecure,
57− MimeRender(..), MimeUnrender,
58− NoContent, QueryFlag, QueryParam,
59− QueryParams, Raw, ReflectMethod(..),
53+import Servant.API ((:<|>) (..), (:>), BasicAuth,
54+ BasicAuthData, BuildHeadersTo (..),
55+ Capture, Header, Headers (..),
56+ HttpVersion, IsSecure,
57+ MimeRender (..), MimeUnrender,
58+ NoContent, QueryFlag, QueryParam',
59+ QueryParams, Raw, ReflectMethod (..),
6060 RemoteHost, ReqBody,
61− ToHttpApiData(..), Vault, Verb)
61+ ToHttpApiData (..), Vault, Verb,
62+ contentType)
63+import Servant.API.Description (Summary)
6264import qualified Servant.Auth as Auth
6365
6466import Reflex.Dom.Core (Dynamic, Event, Reflex,
65− XhrRequest(..),
66− XhrResponseHeaders(..),
67− XhrResponse(..), attachPromptlyDynWith, constDyn, ffor, fmapMaybe,
68− leftmost, performRequestsAsync,
69− )
67+ XhrRequest (..), XhrResponse (..),
68+ XhrResponseHeaders (..),
69+ attachPromptlyDynWith, constDyn, ffor,
70+ fmapMaybe, leftmost,
71+ performRequestsAsync)
7072------------------------------------------------------------------------------
7173import Servant.Common.BaseUrl (BaseUrl(..), Scheme(..), baseUrlWidget,
7274 showBaseUrl,
@@ -327,6 +329,19 @@ instance HasClient t m sublayout tag
327329 clientWithRouteAndResultHandler Proxy =
328330 clientWithRouteAndResultHandler (Proxy :: Proxy sublayout)
329331
332+-- | Using a 'Summary' combinator in your API doesn't affect the client
333+-- functions.
334+instance (HasClient t m sublayout tag, KnownSymbol sym)
335+ => HasClient t m (Summary sym :> sublayout) tag where
336+
337+ type Client t m (Summary sym :> sublayout) tag =
338+ Client t m sublayout tag
339+
340+ clientWithRouteAndResultHandler Proxy =
341+ clientWithRouteAndResultHandler (Proxy :: Proxy sublayout)
342+
343+
344+
330345
331346-- | If you use a 'QueryParam' in one of your endpoints in your API,
332347-- the corresponding querying function will automatically take
@@ -355,9 +370,9 @@ instance HasClient t m sublayout tag
355370-- > -- 'getBooksBy Nothing' for all books
356371-- > -- 'getBooksBy (Just "Isaac Asimov")' to get all books by Isaac Asimov
357372instance (KnownSymbol sym, ToHttpApiData a, HasClient t m sublayout tag, Reflex t)
358− => HasClient t m (QueryParam sym a :> sublayout) tag where
373+ => HasClient t m (QueryParam' mods sym a :> sublayout) tag where
359374
360− type Client t m (QueryParam sym a :> sublayout) tag =
375+ type Client t m (QueryParam' mods sym a :> sublayout) tag =
361376 Dynamic t (QParam a) -> Client t m sublayout tag
362377
363378 -- if mparam = Nothing, we don't add it to the query string
@@ -607,4 +622,3 @@ type family HasCookieAuth xs :: Constraint where
607622 HasCookieAuth '[] = CookieAuthNotEnabled
608623
609624class CookieAuthNotEnabled
610−
src/Servant/Reflex/Multi.hs+35−22
@@ -37,28 +37,30 @@ module Servant.Reflex.Multi (
3737 ) where
3838
3939------------------------------------------------------------------------------
40−import Control.Applicative (liftA2)
41−import Data.Functor.Compose (Compose (..), getCompose)
42−import Data.Proxy (Proxy (..))
43−import qualified Data.Set as Set
44−import Data.Text (Text)
45−import qualified Data.Text as T
46−import qualified Data.Text.Encoding as E
47−import GHC.TypeLits (KnownSymbol, symbolVal)
48−import Servant.API ((:<|>) (..), (:>), BasicAuth,
49− BasicAuthData, BuildHeadersTo (..),
50− Capture, Header, Headers (..),
51− HttpVersion, IsSecure, MimeRender (..),
52− MimeUnrender, NoContent, QueryFlag,
53− QueryParam, QueryParams, Raw,
54− ReflectMethod (..), RemoteHost,
55− ReqBody, ToHttpApiData (..), Vault,
56− Verb, contentType)
57−
58−import Reflex.Dom.Core (Dynamic, Event, Reflex,
59− XhrRequest (..),
60− XhrResponseHeaders (..),
61− attachPromptlyDynWith, constDyn)
40+import Control.Applicative (liftA2)
41+import Data.Functor.Compose (Compose (..), getCompose)
42+import Data.Proxy (Proxy (..))
43+import qualified Data.Set as Set
44+import Data.Text (Text)
45+import qualified Data.Text as T
46+import qualified Data.Text.Encoding as E
47+import GHC.TypeLits (KnownSymbol, symbolVal)
48+import Servant.API ((:<|>) (..), (:>), BasicAuth,
49+ BasicAuthData, BuildHeadersTo (..),
50+ Capture, Header, Headers (..),
51+ HttpVersion, IsSecure,
52+ MimeRender (..), MimeUnrender,
53+ NoContent, QueryFlag, QueryParam,
54+ QueryParams, Raw, ReflectMethod (..),
55+ RemoteHost, ReqBody,
56+ ToHttpApiData (..), Vault, Verb,
57+ contentType)
58+import Servant.API.Description (Summary)
59+
60+import Reflex.Dom.Core (Dynamic, Event, Reflex,
61+ XhrRequest (..),
62+ XhrResponseHeaders (..),
63+ attachPromptlyDynWith, constDyn)
6264------------------------------------------------------------------------------
6365import Servant.Common.BaseUrl (BaseUrl (..), Scheme (..),
6466 SupportsServantReflex)
@@ -240,6 +242,17 @@ instance HasClientMulti t m sublayout f tag
240242 clientWithRouteMulti (Proxy :: Proxy sublayout) q f tag
241243
242244
245+------------------------------------------------------------------------------
246+instance (HasClientMulti t m sublayout f tag, KnownSymbol sym)
247+ => HasClientMulti t m (Summary sym :> sublayout) f tag where
248+
249+ type ClientMulti t m (Summary sym :> sublayout) f tag =
250+ ClientMulti t m sublayout f tag
251+
252+ clientWithRouteMulti Proxy q f tag =
253+ clientWithRouteMulti (Proxy :: Proxy sublayout) q f tag
254+
255+
243256------------------------------------------------------------------------------
244257instance (KnownSymbol sym,
245258 ToHttpApiData a,
travis.nix+1
@@ -48,6 +48,7 @@ in
4848 inherit reflexPlatform ghcPkgs ghcjsPkgs;
4949
5050 build = ghcjsPkgs.servant-reflex;
51+ buildGhc = ghcPkgs.servant-reflex;
5152 testserver = ghcPkgs.testserver;
5253 testdriver = ghcPkgs.testdriver;
5354 inherit testresults;