git.iko.soy/typeable/servant
on master help sign in
server/config: added more documentation
commit09b22452aa62ed1d562bb8fceec953d0b3bac16d authorSönke Hahn <soenkehahn@gmail.com> dateThu 21 Jan 2016, 17:51 (11 years ago) parentdf09f86
5 files changed+53−13
servant-examples/wai-middleware/wai-middleware.hs+1−1 servant-server/src/Servant/Server.hs+3 servant-server/src/Servant/Server/Internal.hs−1 servant-server/src/Servant/Server/Internal/Config.hs+44−2 servant/src/Servant/API/WithNamedConfig.hs+5−9
servant-examples/wai-middleware/wai-middleware.hs+1−1
@@ -41,7 +41,7 @@ server = return products
4141
4242-- logStdout :: Middleware
4343-- i.e, logStdout :: Application -> Application
44−-- serve :: Proxy api -> Config a -> Server api -> Application
44+-- serve :: Proxy api -> Config config -> Server api -> Application
4545-- so applying a middleware is really as simple as
4646-- applying a function to the result of 'serve'
4747app :: Application
servant-server/src/Servant/Server.hs+3
@@ -38,7 +38,10 @@ module Servant.Server
3838
3939 -- * Config
4040 , Config(..)
41+ , HasConfigEntry(getConfigEntry)
42+ -- ** NamedConfig
4143 , NamedConfig(..)
44+ , descendIntoNamedConfig
4245
4346 -- * Default error type
4447 , ServantErr(..)
servant-server/src/Servant/Server/Internal.hs−1
@@ -33,7 +33,6 @@ import Data.String (fromString)
3333import Data.String.Conversions (cs, (<>))
3434import Data.Text (Text)
3535import Data.Typeable
36−import GHC.Exts (Constraint)
3736import GHC.TypeLits (KnownNat, KnownSymbol, natVal,
3837 symbolVal)
3938import Network.HTTP.Types hiding (Header, ResponseHeaders)
servant-server/src/Servant/Server/Internal/Config.hs+44−2
@@ -15,8 +15,18 @@ module Servant.Server.Internal.Config where
1515import Data.Proxy
1616import GHC.TypeLits
1717
18−-- | The entire configuration.
19−data Config a where
18+-- | When calling 'Servant.Server.serve' you have to supply a configuration
19+-- value of type @'Config' configTypes@. This parameter is used to pass values
20+-- to combinators. (It shouldn't be confused with general configuration
21+-- parameters for your web app, like the port, etc.). If you don't use
22+-- combinators that require any config entries, you can just pass 'EmptyConfig'.
23+-- To create a config with entries, use the operator @(':.')@. The parameter of
24+-- the type 'Config' is a type-level list reflecting the types of the contained
25+-- config entries:
26+--
27+-- >>> :type True :. () :. EmptyConfig
28+-- True :. () :. EmptyConfig :: Config '[Bool, ()]
29+data Config configTypes where
2030 EmptyConfig :: Config '[]
2131 (:.) :: x -> Config xs -> Config (x ': xs)
2232infixr 5 :.
@@ -33,6 +43,19 @@ instance Eq (Config '[]) where
3343instance (Eq a, Eq (Config as)) => Eq (Config (a ': as)) where
3444 x1 :. y1 == x2 :. y2 = x1 == x2 && y1 == y2
3545
46+-- | This class is used to access config entries in 'Config's. 'getConfigEntry'
47+-- returns the first value where the type matches:
48+--
49+-- >>> getConfigEntry (True :. False :. EmptyConfig) :: Bool
50+-- True
51+--
52+-- If the 'Config' does not contain an entry of the requested type, you'll get
53+-- an error:
54+--
55+-- >>> getConfigEntry (True :. False :. EmptyConfig) :: String
56+-- ...
57+-- No instance for (HasConfigEntry '[] [Char])
58+-- ...
3659class HasConfigEntry (config :: [*]) (val :: *) where
3760 getConfigEntry :: Config config -> val
3861
@@ -46,9 +69,28 @@ instance OVERLAPPING_
4669
4770-- * support for named subconfigs
4871
72+-- | Normally config entries are accessed by their types. In case you need
73+-- to have multiple values of the same type in your 'Config' and need to access
74+-- them, we provide 'NamedConfig'. You can think of it as sub-namespaces for
75+-- 'Config's.
4976data NamedConfig (name :: Symbol) (subConfig :: [*])
5077 = NamedConfig (Config subConfig)
5178
79+-- | 'descendIntoNamedConfig' allows you to access `NamedConfig's. Usually you
80+-- won't have to use it yourself but instead use a combinator like
81+-- 'Servant.API.WithNamedConfig.WithNamedConfig'.
82+--
83+-- This is how 'descendIntoNamedConfig' works:
84+--
85+-- >>> :set -XFlexibleContexts
86+-- >>> let subConfig = True :. EmptyConfig
87+-- >>> :type subConfig
88+-- subConfig :: Config '[Bool]
89+-- >>> let parentConfig = False :. (NamedConfig subConfig :: NamedConfig "subConfig" '[Bool]) :. EmptyConfig
90+-- >>> :type parentConfig
91+-- parentConfig :: Config '[Bool, NamedConfig "subConfig" '[Bool]]
92+-- >>> descendIntoNamedConfig (Proxy :: Proxy "subConfig") parentConfig :: Config '[Bool]
93+-- True :. EmptyConfig
5294descendIntoNamedConfig :: forall config name subConfig .
5395 HasConfigEntry config (NamedConfig name subConfig) =>
5496 Proxy (name :: Symbol) -> Config config -> Config subConfig
servant/src/Servant/API/WithNamedConfig.hs+5−9
@@ -6,20 +6,16 @@ module Servant.API.WithNamedConfig where
66import GHC.TypeLits
77
88-- | 'WithNamedConfig' names a specific tagged configuration to use for the
9−-- combinators in the API. For example:
9+-- combinators in the API. (See also in @servant-server@,
10+-- @Servant.Server.Config@.) For example:
1011--
11−-- > type UseNamedConfigAPI1 = WithNamedConfig "myConfig" '[String] (
12+-- > type UseNamedConfigAPI = WithNamedConfig "myConfig" '[String] (
1213-- > ReqBody '[JSON] Int :> Get '[JSON] Int)
1314--
1415-- Both the 'ReqBody' and 'Get' combinators will use the 'NamedConfig' with
15−-- type tag "myConfig" as their configuration. In constrast, in (notice
16−-- parentesizing):
16+-- type tag "myConfig" as their configuration.
1717--
18−-- > type UseNamedConfigAPI2 = WithNamedConfig "myConfig" '[String] (
19−-- > ReqBody '[JSON] Int) :> Get '[JSON] Int
20−--
21−-- Only the 'ReqBody' combinator will use this configuration, and 'Get' will
22−-- maintain the default configuration.
18+-- 'Config's are only relevant for @servant-server@.
2319--
2420-- For more information, see the tutorial.
2521data WithNamedConfig (name :: Symbol) (subConfig :: [*]) subApi