packages feed

Shpadoinkle-router 0.2.0.1 → 0.3.0.0

raw patch · 3 files changed

+60/−37 lines, 3 filesdep +http-typesdep +servant-rawmdep +servant-rawm-serverdep ~servant-clientPVP ok

version bump matches the API change (PVP)

Dependencies added: http-types, servant-rawm, servant-rawm-server

Dependency ranges changed: servant-client

API changes (from Hackage documentation)

+ Shpadoinkle.Router: data RawM' serverType
+ Shpadoinkle.Router: instance Shpadoinkle.Router.HasRouter (Servant.RawM.RawM' serverType)
+ Shpadoinkle.Router: type RawM = RawM' FileServer
+ Shpadoinkle.Router.Server: serveHtml :: Html m a -> Application
- Shpadoinkle.Router: [RCapture] :: FromHttpApiData x => (x -> Router a) -> Router a
+ Shpadoinkle.Router: [RCapture] :: (Text -> Either Text x) -> (x -> Router a) -> Router a
- Shpadoinkle.Router: [RQueryParamR] :: (FromHttpApiData x, KnownSymbol sym) => Proxy sym -> (x -> Router a) -> Router a
+ Shpadoinkle.Router: [RQueryParamR] :: KnownSymbol sym => (Text -> Either Text x) -> Proxy sym -> (x -> Router a) -> Router a
- Shpadoinkle.Router: [RQueryParam] :: (FromHttpApiData x, KnownSymbol sym) => Proxy sym -> (Maybe x -> Router a) -> Router a
+ Shpadoinkle.Router: [RQueryParam] :: KnownSymbol sym => (Text -> Either Text x) -> Proxy sym -> (Maybe x -> Router a) -> Router a
- Shpadoinkle.Router: [RQueryParams] :: (FromHttpApiData x, KnownSymbol sym) => Proxy sym -> ([x] -> Router a) -> Router a
+ Shpadoinkle.Router: [RQueryParams] :: KnownSymbol sym => (Text -> Either Text x) -> Proxy sym -> ([x] -> Router a) -> Router a
- Shpadoinkle.Router.Server: serveDirectoryWithSpa :: StaticSettings -> ServerT (View m a) n
+ Shpadoinkle.Router.Server: serveDirectoryWithSpa :: Applicative n => StaticSettings -> ServerT (View m a) n

Files

Shpadoinkle-router.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 287b71ef93760ce3e427d0d14f772ed6bee4c147edd12b6879f767ff727d2f7b+-- hash: 3c7184e4c455d500951338935b68b93a593204314315d262e725f0540ee0bbd9  name:           Shpadoinkle-router-version:        0.2.0.1+version:        0.3.0.0 synopsis:       A single page application rounter for Shpadoinkle based on Servant. description:    Surjective single page application routing with Servant. Surjectivity in this context means routes can be backward compatible, allowing URLs to evolve. Since routes are specified as Servant combinators, serving these routes from the backend is trivial. For an example of leveraging the client-server isomorphism via Servant specification, check the servant-crud example. category:       Web@@ -48,6 +48,7 @@     , lens >=4.17.1 && <5.0     , network-uri >=2.6.1 && <2.8     , servant >=0.16 && <0.19+    , servant-rawm     , text >=1.2.3 && <1.3     , unliftio >=0.2.12 && <0.3   if impl(ghcjs)@@ -56,9 +57,11 @@   else     build-depends:         Shpadoinkle-backend-static+      , http-types       , jsaddle-warp-      , servant-client >=0.16.0 && <0.18+      , servant-client >=0.15.0 && <0.19       , servant-client-js >=0.1 && <0.2+      , servant-rawm-server       , servant-server >=0.16 && <0.18       , wai >=3.2.2 && <3.3       , wai-app-static >=3.1.6 && <3.2
Shpadoinkle/Router.hs view
@@ -40,7 +40,7 @@     -- * Rehydration     , withHydration, toHydration     -- * Re-Exports-    , Raw, MonadJSM, HasLink(..)+    , Raw, S.RawM', S.RawM, MonadJSM, HasLink(..)     ) where  @@ -74,24 +74,25 @@                                                 IsElem, MimeRender (..),                                                 QueryFlag, QueryParam,                                                 QueryParam', QueryParams, Raw,-                                                Required, type (:<|>) (..),-                                                type (:>))+                                                Required, parseQueryParam,+                                                type (:<|>) (..), type (:>)) #else import           Servant.API                   (Capture, FromHttpApiData,                                                 HasLink (..), IsElem, QueryFlag,                                                 QueryParam, QueryParam',                                                 QueryParams, Raw, Required,+                                                parseQueryParam,                                                 type (:<|>) (..), type (:>)) #endif import           Servant.Links                 (Link, URI (..), linkURI,                                                 safeLink)+import qualified Servant.RawM                  as S import           System.IO.Unsafe              (unsafePerformIO) import           UnliftIO.Concurrent           (MVar, forkIO, newEmptyMVar,                                                 putMVar, takeMVar) import           UnliftIO.STM                  (TVar, atomically, newTVarIO,                                                 writeTVar)-import           Web.HttpApiData               (parseQueryParamMaybe,-                                                parseUrlPieceMaybe)+import           Web.HttpApiData               (parseUrlPiece)  import           Shpadoinkle                   (Backend, Continuation, Html,                                                 RawNode, h, hoist, kleisli, pur,@@ -104,8 +105,8 @@ import qualified Data.ByteString.Lazy          as BSL import qualified Data.List.NonEmpty            as NE import qualified Network.HTTP.Media            as M-import           Servant                       (Application, HasServer, Tagged) import qualified Servant                       as S+import           Servant.RawM.Server           ()  import           Shpadoinkle.Backend.Static    (renderStatic) @@ -119,10 +120,10 @@ -- | Term level API representation data Router a where   RChoice      :: Router a -> Router a -> Router a-  RCapture     :: FromHttpApiData x => (x -> Router a) -> Router a-  RQueryParam  :: (FromHttpApiData x, KnownSymbol sym) => Proxy sym -> (Maybe x -> Router a) -> Router a-  RQueryParamR :: (FromHttpApiData x, KnownSymbol sym) => Proxy sym -> (x -> Router a) -> Router a-  RQueryParams :: (FromHttpApiData x, KnownSymbol sym) => Proxy sym -> ([x] -> Router a) -> Router a+  RCapture     :: (Text -> Either Text x) -> (x -> Router a) -> Router a+  RQueryParam  :: KnownSymbol sym => (Text -> Either Text x) -> Proxy sym -> (Maybe x -> Router a) -> Router a+  RQueryParamR :: KnownSymbol sym => (Text -> Either Text x) -> Proxy sym -> (x -> Router a) -> Router a+  RQueryParams :: KnownSymbol sym => (Text -> Either Text x) -> Proxy sym -> ([x] -> Router a) -> Router a   RQueryFlag   :: KnownSymbol sym => Proxy sym -> (Bool -> Router a) -> Router a   RPath        :: KnownSymbol sym => Proxy sym -> Router a -> Router a   RView        :: a -> Router a@@ -330,23 +331,23 @@   return ()  --- | Get an @r@ from a route and URL context+-- | Get an @r@ from a route and url context fromRouter :: [(Text,Text)] -> [Text] -> Router r -> Maybe r fromRouter queries segs = \case-    RChoice x y        -> fromRouter queries segs x <|> fromRouter queries segs y-    RCapture f         -> case segs of-        []                 -> Nothing-        capture:paths      -> fromRouter queries paths . f =<< parseUrlPieceMaybe capture-    RQueryParam sym f  ->+    RChoice x y                -> fromRouter queries segs x <|> fromRouter queries segs y+    RCapture decoder f         -> case segs of+        []            -> Nothing+        capture:paths -> fromRouter queries paths . f =<< mabify decoder capture+    RQueryParam decoder sym f  ->         case lookup (T.pack $ symbolVal sym) queries of             Nothing -> fromRouter queries segs $ f Nothing-            Just t  -> fromRouter queries segs $ f (parseQueryParamMaybe t)-    RQueryParamR sym f ->+            Just t  -> fromRouter queries segs $ f (mabify decoder t)+    RQueryParamR decoder sym f ->        case lookup (T.pack $ symbolVal sym) queries of             Nothing -> Nothing-            Just t  -> fromRouter queries segs . f =<< parseQueryParamMaybe t-    RQueryParams sym f ->-        fromRouter queries segs . f . compact $ parseQueryParamMaybe . snd <$> C.filter+            Just t  -> fromRouter queries segs . f =<< mabify decoder t+    RQueryParams decoder sym f ->+        fromRouter queries segs . f . compact $ mabify decoder . snd <$> C.filter             (\(k, _) -> k == T.pack (symbolVal sym))             queries     RQueryFlag sym f ->@@ -356,6 +357,11 @@         p:paths            -> if p == T.pack (symbolVal sym) then             fromRouter queries paths a else Nothing     RView a            -> if null segs then Just a else Nothing+  where+    mabify :: (x -> Either e a) -> (x -> Maybe a)+    mabify f input = case f input of+                      (Left _)  -> Nothing+                      (Right x) -> Just x   -- | This type class traverses the Servant API and sets up a function to@@ -384,7 +390,7 @@     type (Capture sym x :> sub) :>> a = x -> sub :>> a      route :: (x -> sub :>> r) -> Router r-    route = RCapture . (route @sub .)+    route = RCapture parseUrlPiece . (route @sub .)     {-# INLINABLE route #-}  instance (HasRouter sub, FromHttpApiData x, KnownSymbol sym)@@ -393,7 +399,7 @@     type (QueryParam sym x :> sub) :>> a = Maybe x -> sub :>> a      route :: (Maybe x -> sub :>> r) -> Router r-    route = RQueryParam (Proxy @sym) . (route @sub .)+    route = RQueryParam parseQueryParam (Proxy @sym) . (route @sub .)     {-# INLINABLE route #-}  instance (HasRouter sub, FromHttpApiData x, KnownSymbol sym)@@ -402,7 +408,7 @@   type (QueryParam' '[Required] sym x :> sub) :>> a = x -> sub :>> a    route :: (x -> sub :>> r) -> Router r-  route = RQueryParamR (Proxy @sym) . (route @sub .)+  route = RQueryParamR parseQueryParam (Proxy @sym) . (route @sub .)  instance (HasRouter sub, FromHttpApiData x, KnownSymbol sym)     => HasRouter (QueryParams sym x :> sub) where@@ -410,7 +416,7 @@     type (QueryParams sym x :> sub) :>> a = [x] -> sub :>> a      route :: ([x] -> sub :>> r) -> Router r-    route = RQueryParams (Proxy @sym) . (route @sub .)+    route = RQueryParams parseQueryParam (Proxy @sym) . (route @sub .)     {-# INLINABLE route #-}  instance (HasRouter sub, KnownSymbol sym)@@ -438,6 +444,13 @@     route = RView     {-# INLINABLE route #-} +instance HasRouter (S.RawM' serverType) where+    type S.RawM' serverType :>> a = a++    route :: r -> Router r+    route = RView+    {-# INLINABLE route #-}+ instance HasRouter (f '[HTML] (Html m b)) where     type f '[HTML] (Html m b) :>> a = a @@ -466,10 +479,10 @@   mimeRender _ =  BSL.fromStrict . encodeUtf8 . renderStatic  -instance HasServer (View m a) context where-  type ServerT (View m a) m' = Tagged m' Application-  route _                   = S.route          (Proxy @Raw)-  hoistServerWithContext _  = S.hoistServerWithContext (Proxy @Raw)+instance S.HasServer (View m a) context where+  type ServerT (View m a) n = S.ServerT S.RawM n+  route _                    = S.route                  (Proxy @S.RawM)+  hoistServerWithContext _   = S.hoistServerWithContext (Proxy @S.RawM)   #endif
Shpadoinkle/Router/Server.hs view
@@ -27,15 +27,16 @@  import           Data.ByteString.Lazy           as BS (ByteString, fromStrict,                                                        length)+import qualified Data.ByteString.Lazy           as BSL import           Data.Text.Encoding             (encodeUtf8) import           GHC.TypeLits                   (Symbol)-import           Network.Wai                    (responseLBS)+import           Network.HTTP.Types+import           Network.Wai                    (Application, responseLBS) import           Network.Wai.Application.Static (StaticSettings (ssLookupFile, ssMaxAge),                                                  defaultWebAppSettings,                                                  staticApp) import           Servant.API-import           Servant.Server                 (HasServer (ServerT), Server,-                                                 Tagged (Tagged))+import           Servant.Server                 (HasServer (ServerT), Server) import           Servant.Server.StaticFiles     (serveDirectoryWith) import           WaiAppStatic.Types             (File (..),                                                  LookupResult (LRFile, LRNotFound),@@ -145,6 +146,12 @@   {-# INLINABLE serveUI #-}  -serveDirectoryWithSpa :: StaticSettings -> ServerT (View m a) n-serveDirectoryWithSpa = Tagged . staticApp+serveDirectoryWithSpa :: Applicative n => StaticSettings -> ServerT (View m a) n+serveDirectoryWithSpa = pure . staticApp+++serveHtml :: Html m a -> Application+serveHtml html _ respond+  = respond . responseLBS status200 [(hContentType, "text/html")]+  . BSL.fromStrict . encodeUtf8 $ renderStatic html #endif