Skip to content

Commit 75d8ff6

Browse files
committed
version 0.1.0.3: updated library; added documentation
1 parent 8c01ac9 commit 75d8ff6

File tree

8 files changed

+130
-85
lines changed

8 files changed

+130
-85
lines changed

README.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,44 @@
11
# web-template
2+
3+
This is library that encapsulate settings and error-catching for REST-services.
4+
5+
Convention, that are inside:
6+
7+
* every route has the following structure: `HOST:PORT/v{PATH VERSION}/PATH`;
8+
* every path can be under authorization. Authorization means that server will look for the field `id` in Cookies.
9+
10+
## Example
11+
12+
Look for example in `add/Main.hs` file. To run simple server on port 5000 just run:
13+
```
14+
stack build
15+
stack exec web-template
16+
```
17+
18+
Then you can ask server with curl requests:
19+
20+
* not processing path:
21+
```
22+
>>> curl localhost:5000/abracadabra
23+
<h1>404: File Not Found!</h1>
24+
```
25+
26+
* processing path with no authorization needed:
27+
```
28+
>>> curl localhost:5000/v1/ping
29+
Pong!
30+
Current environment: 0.%
31+
```
32+
33+
* processing path with authorization without authorization:
34+
```
35+
>>> curl localhost:5000/v1/pong
36+
{"error":"Authorization failed"}
37+
```
38+
39+
* processing path with authorization with authorization:
40+
```
41+
>>> curl localhost:5000/v1/pong --cookie "id=0000-0000-0000-000000000000"
42+
Ping!
43+
Authorised: 0000-0000-0000-000000000000.
44+
```

app/Main.hs

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,27 @@
22

33
module Main where
44

5-
import Control.Monad.Reader (ask, lift, liftIO)
6-
import Data.Text (unpack)
5+
import Control.Monad.Reader (ask, lift)
6+
import Data.Text (pack)
7+
import Data.Text.Lazy (fromStrict)
8+
import Text.Printf (printf)
79
import Web.Scotty.Trans (get, text)
810
import Web.Template (CustomWebServer (..), Process (..),
911
Route (..), runWebServer)
1012

1113

12-
1314
main :: IO ()
14-
main = let myState = True
15-
myWebServer = CustomWebServer myState [ Route get 1 "/ping" pingR
16-
, Route get 1 "/pong" pongR
17-
]
18-
in runWebServer myWebServer
15+
main = runWebServer 5000 myWebServer
16+
where env = 0
17+
myWebServer = CustomWebServer env [ Route get 1 "/ping" pingR
18+
, Route get 1 "/pong" pongR
19+
]
1920

20-
pingR :: Process Bool
21+
pingR :: Process Int
2122
pingR = Process $ do
22-
state <- lift ask
23-
liftIO $ print state
24-
text "Pong!"
23+
env <- lift ask
24+
text . fromStrict . pack $ printf "Pong!\nCurrent environment: %d." env
2525

26-
pongR :: Process Bool
27-
pongR = AuthProcess $ \userId -> do
28-
liftIO . print $ "Authorised: " ++ unpack userId
29-
text "Ping!"
26+
pongR :: Process Int
27+
pongR = AuthProcess $ \userId ->
28+
text . fromStrict . pack $ printf "Ping!\nAuthorised: %s." userId

src/Web/Template.hs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
module Web.Template
2-
( Route (..), WebM, CustomWebServer(..)
3-
, UserId, Process (..)
4-
, ServerConfig (..)
2+
( UserId, Port, Env, WebM, ScottyM
3+
, CustomWebServer (..), Process (..), Route (..)
4+
, runWebServer
55
, JsonWebError (..)
6-
, runWebServer, runWebServerConf
76
) where
87

9-
import Web.Template.Server (CustomWebServer (..), Process (..),
10-
Route (..), runWebServer,
11-
runWebServerConf)
12-
import Web.Template.Types (UserId, WebM, ServerConfig (..))
13-
import Web.Template.Except (JsonWebError (..))
8+
import Web.Template.Except (JsonWebError (..))
9+
import Web.Template.Server (CustomWebServer (..), Env, Port,
10+
Process (..), Route (..), ScottyM, UserId,
11+
WebM, runWebServer)

src/Web/Template/Except.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
{-# LANGUAGE DeriveGeneric #-}
2+
23
module Web.Template.Except
34
( Except (..), JsonWebError (..)
45
, handleEx

src/Web/Template/Server.hs

Lines changed: 47 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@
22
{-# LANGUAGE RecordWildCards #-}
33

44
module 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)
1011
import Data.String (fromString)
12+
import Data.Text as T (Text)
1113
import Data.Text.Encoding (encodeUtf8)
1214
import Data.Text.Lazy as TL (Text, toStrict)
1315
import Network.HTTP.Types.Status (status401, status405)
@@ -16,54 +18,69 @@ import Network.Wai.Handler.Warp (defaultSettings,
1618
setOnExceptionResponse,
1719
setPort)
1820
import Network.Wai.Middleware.RequestLogger (logStdoutDev)
19-
import Options.Generic (getRecord)
2021
import 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.
3348
data 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 ()
5876
runRoute 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 ()
6784
auth (Process p) = p
6885
auth (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 ()
7794
checkVersion 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

84101
getIdFromCookies :: TL.Text -> Maybe UserId
85102
getIdFromCookies cookies = lookup "id" $ parseCookiesText $ encodeUtf8 $ toStrict cookies

src/Web/Template/Types.hs

Lines changed: 0 additions & 27 deletions
This file was deleted.

stack.yaml

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
1-
resolver: lts-9.3
1+
# before building, don`t forget to delete the cache file ~/.stack/custom-plan/yaml/
2+
3+
resolver: https://lts.math.bio/bcd-lts-dev.yaml
4+
5+
package-indices:
6+
- name: LTS-index
7+
download-prefix: https://hackage.math.bio/hackage.fpcomplete.com/package/
8+
http: https://hackage.math.bio/hackage.fpcomplete.com/00-index.tar.gz
9+
- name: Hackage Biocad
10+
download-prefix: http://hackage.biocad.ru/package/
11+
http: http://hackage.biocad.ru/00-index.tar.gz
212

313
packages:
414
- .
@@ -8,3 +18,8 @@ extra-deps: []
818
flags: {}
919

1020
extra-package-dbs: []
21+
22+
ignore-revision-mismatch: true
23+
24+
ghc-options:
25+
$locals: -Wall -fdiagnostics-color=always

web-template.cabal

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: web-template
2-
version: 0.1.0.2
2+
version: 0.1.0.3
33
synopsis: Web template
44
description:
55
Web template includes:
@@ -22,7 +22,6 @@ library
2222
hs-source-dirs: src
2323
exposed-modules: Web.Template
2424
other-modules: Web.Template.Except
25-
, Web.Template.Types
2625
, Web.Template.Server
2726
build-depends: base >= 4.7 && < 5
2827
, scotty

0 commit comments

Comments
 (0)