git.iko.soy/typeable/servant
on master help sign in
Better docs for servant-server
commitbdf6d9aa4815c1705bf2f27122f394498f6379f8 authorJulian K. Arni <jkarni@gmail.com> dateSun 3 May 2015, 01:28 (11 years ago) parent3b4b958
3 files changed+65−13
servant-server/src/Servant/Server.hs+55−10 servant-server/src/Servant/Server/Internal/Enter.hs+10−2 servant-server/test/Servant/Server/Internal/EnterSpec.hs−1
servant-server/src/Servant/Server.hs+55−10
@@ -1,6 +1,7 @@
1−{-# LANGUAGE TypeFamilies #-}
2−{-# LANGUAGE FlexibleContexts #-}
1+{-# LANGUAGE CPP #-}
2+{-# LANGUAGE FlexibleContexts #-}
33{-# LANGUAGE OverloadedStrings #-}
4+{-# LANGUAGE TypeFamilies #-}
45
56-- | This module lets you implement 'Server's for defined APIs. You'll
67-- most likely just need 'serve'.
@@ -17,8 +18,27 @@ module Servant.Server
1718 , ServerT
1819
1920 -- * Enter
20− -- Applying functions to all handlers
21− , Enter(..)
21+ -- $enterDoc
22+
23+ -- ** Basic functions and datatypes
24+ , enter
25+ , (:~>)(..)
26+ -- ** `Nat` utilities
27+ , liftNat
28+ , runReaderTNat
29+ , evalStateTLNat
30+ , evalStateTSNat
31+ , logWriterTLNat
32+ , logWriterTSNat
33+#if MIN_VERSION_mtl(2,2,1)
34+ , fromExceptT
35+#endif
36+ -- ** Functions based on <https://hackage.haskell.org/package/mmorph mmorph>
37+ , hoistNat
38+ , embedNat
39+ , squashNat
40+ , generalizeNat
41+
2242
2343 -- * Default error type
2444 , ServantErr(..)
@@ -58,12 +78,12 @@ module Servant.Server
5878
5979 ) where
6080
61−import Data.Proxy (Proxy)
62−import Network.Wai (Application)
63−import Servant.API (Canonicalize, canonicalize)
64−import Servant.Server.Internal
65−import Servant.Server.Internal.ServantErr
66−import Servant.Server.Internal.Enter
81+import Data.Proxy (Proxy)
82+import Network.Wai (Application)
83+import Servant.API (Canonicalize, canonicalize)
84+import Servant.Server.Internal
85+import Servant.Server.Internal.Enter
86+import Servant.Server.Internal.ServantErr
6787
6888
6989-- * Implementing Servers
@@ -88,5 +108,30 @@ import Servant.Server.Internal.Enter
88108-- >
89109-- > main :: IO ()
90110-- > main = Network.Wai.Handler.Warp.run 8080 app
111+--
91112serve :: HasServer (Canonicalize layout) => Proxy layout -> Server layout -> Application
92113serve p server = toApplication (route (canonicalize p) server)
114+
115+
116+-- Documentation
117+
118+-- $enterDoc
119+-- Sometimes our cherished `EitherT` monad isn't quite the type you'd like for
120+-- your handlers. Maybe you want to thread some configuration in a @Reader@
121+-- monad. Or have your types ensure that your handlers don't do any IO. Enter
122+-- `enter`.
123+--
124+-- With `enter`, you can provide a function, wrapped in the `(:~>)` / `Nat`
125+-- newtype, to convert any number of endpoints from one type constructor to
126+-- another. For example
127+--
128+-- >>> import Control.Monad.Reader
129+-- >>> import qualified Control.Category as C
130+-- >>> type ReaderAPI = "ep1" :> Get '[JSON] Int :<|> "ep2" :> Get '[JSON] String
131+-- >>> let readerServer = return 1797 :<|> ask :: ServerT ReaderAPI (Reader String)
132+-- >>> let mainServer = enter (generalizeNat C.. (runReaderTNat "hi")) readerServer :: Server ReaderAPI
133+--
134+
135+-- $setup
136+-- >>> import Servant.API
137+-- >>> import Servant.Server
servant-server/src/Servant/Server/Internal/Enter.hs+10−2
@@ -21,7 +21,9 @@ import Control.Monad.Morph
2121import Control.Monad.Reader
2222import qualified Control.Monad.State.Lazy as LState
2323import qualified Control.Monad.State.Strict as SState
24+#if MIN_VERSION_mtl(2,2,1)
2425import Control.Monad.Trans.Either
26+#endif
2527import qualified Control.Monad.Writer.Lazy as LWriter
2628import qualified Control.Monad.Writer.Strict as SWriter
2729import Data.Typeable
@@ -41,6 +43,8 @@ instance (Enter b arg ret) => Enter (a -> b) arg (a -> ret) where
4143
4244-- ** Useful instances
4345
46+-- | A natural transformation from @m@ to @n@. Used to `enter` particular
47+-- datatypes.
4448newtype m :~> n = Nat { unNat :: forall a. m a -> n a} deriving Typeable
4549
4650instance C.Category (:~>) where
@@ -50,8 +54,9 @@ instance C.Category (:~>) where
5054instance Enter (m a) (m :~> n) (n a) where
5155 enter (Nat f) = f
5256
53−liftNat :: (MonadTrans t, Monad m) => m :~> t m
54−liftNat = Nat lift
57+-- | Like `lift`.
58+liftNat :: (Control.Monad.Morph.MonadTrans t, Monad m) => m :~> t m
59+liftNat = Nat Control.Monad.Morph.lift
5560
5661runReaderTNat :: r -> (ReaderT r m :~> m)
5762runReaderTNat a = Nat (`runReaderT` a)
@@ -86,11 +91,14 @@ fromExceptT = Nat $ \x -> EitherT $ runExceptT x
8691hoistNat :: (MFunctor t, Monad m) => (m :~> n) -> (t m :~> t n)
8792hoistNat (Nat n) = Nat $ hoist n
8893
94+-- | Like @mmorph@'s `embed`.
8995embedNat :: (MMonad t, Monad n) => (m :~> t n) -> (t m :~> t n)
9096embedNat (Nat n) = Nat $ embed n
9197
98+-- | Like @mmorph@'s `squash`.
9299squashNat :: (Monad m, MMonad t) => t (t m) :~> t m
93100squashNat = Nat squash
94101
102+-- | Like @mmorph@'s `generalize`.
95103generalizeNat :: Applicative m => Identity :~> m
96104generalizeNat = Nat (pure . runIdentity)
servant-server/test/Servant/Server/Internal/EnterSpec.hs−1
@@ -9,7 +9,6 @@ import Control.Monad.Trans.Either
99import Data.Proxy
1010import Servant.API
1111import Servant.Server
12−import Servant.Server.Internal.Enter
1312
1413import Test.Hspec (Spec, describe, it)
1514import Test.Hspec.Wai (get, matchStatus, post,