wai-routes-0.2.1: examples/Example.hs
{-# LANGUAGE OverloadedStrings, TemplateHaskell, QuasiQuotes, TypeFamilies #-}
module Main where
import Network.Wai
import Network.Wai.Middleware.Routes
import Network.Wai.Application.Static
import Network.Wai.Handler.Warp
import Network.HTTP.Types
import qualified Data.Text as T
import Data.Text (Text)
import Data.Aeson
import Data.IORef
import qualified Data.Map as M
import Control.Monad.Trans
-- The database of users
data User = User
{ userId :: Int
, userName :: Text
, userAge :: Int
} deriving (Show, Read, Eq)
type DB = [User]
-- JSON instance
instance ToJSON User where
toJSON x = object [ "uid" .= userId x, "name" .= userName x, "age" .= userAge x ]
-- The Site argument
data MyRoute = MyRoute (IORef DB)
-- Make MyRoute Routable
mkRoute "MyRoute" [parseRoutes|
/ HomeR GET
/users UsersR GET
/user/#Int UserR:
/ UserRootR GET
/delete UserDeleteR GET POST
|]
-- Our handlers always produce json
jsonHeaders :: ResponseHeaders
jsonHeaders = [("Content-Type", "application/json")]
-- Handlers
-- Display the possible actions
getHomeR :: Handler MyRoute
getHomeR _master _req = return $ responseLBS status200 jsonHeaders jsonOut
where jsonOut = encode $ M.fromList (
[("description", [["Simple User database Example"]])
,("links"
,[["home", showRoute HomeR]
,["users", showRoute UsersR]
]
)
] :: [(Text, [[Text]])] )
-- Display all the users
getUsersR :: Handler MyRoute
getUsersR (MyRoute dbref) _req = do
db <- liftIO $ readIORef dbref
let dblinks = map linkify db
let jsonOut = encode $ M.fromList (
[("description", [["Users List"]])
,("links", dblinks)] :: [(Text, [[Text]])] )
return $ responseLBS status200 jsonHeaders jsonOut
where
linkify user = [userName user, showRoute $ UserR (userId user) UserRootR]
-- Display a single user
getUserRootR :: Int -> Handler MyRoute
getUserRootR i (MyRoute dbref) _req = do
db <- liftIO $ readIORef dbref
case ulookup i db of
Nothing -> return $ responseLBS status200 jsonHeaders $ encode ("ERROR: User not found" :: Text)
Just user -> do
let jsonOut = encode $ M.fromList (
[("description", [["User details"]])
,("data"
,[["Id", T.pack $ show $ userId user]
,["Name", userName user]
,["Age", T.pack $ show $ userAge user]
]
)
,("links"
,[["details", showRoute $ UserR (userId user) UserRootR]
,["delete (post only)", showRoute $ UserR (userId user) UserDeleteR]
]
)
] :: [(Text, [[Text]])] )
return $ responseLBS status200 jsonHeaders jsonOut
where
ulookup _ [] = Nothing
ulookup ui (u:us) = if userId u == ui then Just u else ulookup ui us
-- Delete a user: GET
getUserDeleteR :: Int -> Handler MyRoute
getUserDeleteR _ _master _req = return $ responseLBS status200 jsonHeaders jsonOut
where err = ["DELETE","please use POST"]::[Text]
jsonOut = encode err
-- Delete a user: POST
postUserDeleteR :: Int -> Handler MyRoute
postUserDeleteR _ _master _req = return $ responseLBS status200 jsonHeaders jsonOut
where err = ["DELETE","not implemented"]::[Text]
jsonOut = encode err
-- Initial database
initdb :: [User]
initdb =
[ User 1 "Anon Amos" 23
, User 2 "Bo Lively" 28
]
-- The application that uses our route
-- NOTE: We use the Route Monad to simplify routing
application :: RouteM ()
application = do
db <- liftIO $ newIORef initdb
route (MyRoute db)
defaultAction $ staticApp $ defaultFileServerSettings "static"
-- Run the application
main :: IO ()
main = toWaiApp application >>= run 8080