22{-# LANGUAGE RecordWildCards #-}
33
44module Web.Template.Server
5- ( CustomWebServer (.. ), Process (.. ), Route (.. )
6- , runWebServerConf , runWebServer
5+ ( UserId , Port , Env , WebM , ScottyM
6+ , CustomWebServer (.. ), Process (.. ), Route (.. )
7+ , runWebServer
78 ) where
89
9- import Control.Monad.Reader
10+ import Control.Monad.Reader ( ReaderT ( .. ), runReaderT )
1011import Data.String (fromString )
12+ import Data.Text as T (Text )
1113import Data.Text.Encoding (encodeUtf8 )
1214import Data.Text.Lazy as TL (Text , toStrict )
1315import Network.HTTP.Types.Status (status401 , status405 )
@@ -16,54 +18,69 @@ import Network.Wai.Handler.Warp (defaultSettings,
1618 setOnExceptionResponse ,
1719 setPort )
1820import Network.Wai.Middleware.RequestLogger (logStdoutDev )
19- import Options.Generic (getRecord )
2021import Web.Cookie (parseCookiesText )
21- import Web.Scotty.Trans (Options (.. ),
22+ import Web.Scotty.Trans (ActionT , Options (.. ),
2223 RoutePattern , ScottyT ,
2324 defaultHandler , header ,
2425 json , middleware , param ,
2526 scottyOptsT , status )
26- import Web.Template.Except (Except , JsonWebError (.. ),
27+ import Web.Template.Except (Except ,
28+ JsonWebError (.. ),
2729 handleEx )
28- import Web.Template.Types (ServerConfig (.. ), ScottyM ,
29- UserId , WebM )
3030
31+ -- | Alias for UserId.
32+ type UserId = T. Text
3133
34+ -- | Alias for Port.
35+ type Port = Int
3236
37+ -- | Alias for environment.
38+ type Env env = ReaderT env IO
39+
40+ -- | Alias for Web monad. Incapsulates 'Web.Scotty.Trans.ActionT'.
41+ type WebM env a = ActionT Except (Env env ) a
42+
43+ -- | Alias for Scotty monad. Encapsulates 'Web.Scotty.Trans.ScottyT'
44+ type ScottyM env a = ScottyT Except (Env env ) a
45+
46+ -- | 'Process' encapsulates what we what to do inside 'Route'.
47+ -- If your need to check authorization then use 'AuthProcess' constructor.
3348data Process s = Process (WebM s () )
3449 | AuthProcess (UserId -> WebM s () )
3550
36- data Route s = Route { method :: RoutePattern -> WebM s () -> ScottyT Except (ReaderT s IO ) ()
37- , version :: Int
38- , path :: String
39- , process :: Process s
40- }
51+ -- | 'Route' include every needed information to make some stuff with request. It includes:
52+ -- * environment @env@ that we can store and use (for example, connections for databases);
53+ -- * method (like POST or GET);
54+ -- * version of path (it should be like `/v{Integer}/`);
55+ -- * path (just name of path);
56+ -- * process (what should we do with request).
57+ data Route env = Route { method :: RoutePattern -> WebM env () -> ScottyT Except (Env env ) ()
58+ , version :: Int
59+ , path :: String
60+ , process :: Process env
61+ }
4162
42- data CustomWebServer s = CustomWebServer { initialState :: s
43- , routes :: [Route s ]
44- }
63+ -- | Contains environment and processing routes.
64+ data CustomWebServer env = CustomWebServer { environment :: env
65+ , routes :: [Route env ]
66+ }
4567
46- runWebServerConf :: ServerConfig -> CustomWebServer s -> IO ()
47- runWebServerConf conf CustomWebServer {.. } = scottyOptsT (scottyOpts conf) (`runReaderT` initialState) $ do
68+ -- | For given port and server settings run the server.
69+ runWebServer :: Port -> CustomWebServer env -> IO ()
70+ runWebServer port CustomWebServer {.. } = scottyOptsT (scottyOpts port) (`runReaderT` environment) $ do
4871 middleware logStdoutDev
4972 defaultHandler handleEx
5073 mapM_ runRoute routes
5174
52- runWebServer :: CustomWebServer s -> IO ()
53- runWebServer cws = do
54- conf <- getRecord " Web template"
55- runWebServerConf conf cws
56-
57- runRoute :: Route s -> ScottyM s ()
75+ runRoute :: Route env -> ScottyM env ()
5876runRoute Route {.. } = method (fromString $ " /:version" ++ path) (checkVersion version . auth $ process)
5977
60-
61- scottyOpts :: ServerConfig -> Options
62- scottyOpts ServerConfig {.. } = Options 1 warpSettings
78+ scottyOpts :: Port -> Options
79+ scottyOpts port = Options 1 warpSettings
6380 where warpSettings = setOnExceptionResponse exceptionResponseForDebug .
6481 setPort port $ defaultSettings
6582
66- auth :: Process s -> WebM s ()
83+ auth :: Process env -> WebM env ()
6784auth (Process p) = p
6885auth (AuthProcess p) = do
6986 cookiesM <- header " Cookie"
@@ -73,13 +90,13 @@ auth (AuthProcess p) = do
7390 Nothing -> do status status401
7491 json . JsonWebError $ " Authorization failed"
7592
76- checkVersion :: Int -> WebM s () -> WebM s ()
93+ checkVersion :: Int -> WebM env () -> WebM env ()
7794checkVersion version route = do
7895 versionPath <- param " version" :: WebM s String
7996 if " v" ++ show version == versionPath
8097 then route
8198 else do status status405
82- json . JsonWebError $ " Server API version: " ++ show version ++ " ; got version: " ++ versionPath
99+ json . JsonWebError $ " Server API version: " ++ show version ++ " ; got version: " ++ versionPath
83100
84101getIdFromCookies :: TL. Text -> Maybe UserId
85102getIdFromCookies cookies = lookup " id" $ parseCookiesText $ encodeUtf8 $ toStrict cookies
0 commit comments