Happstack.Lite
module, so you don’t need to search the modules for what you need.import Happstack.Lite
to replace import Happstack.Server
serve Nothing
to replace with simpleHTTP nullConf
import Control.Monad (msum)
decodeBody
call ( details ) {-# LANGUAGE OverloadedStrings, ScopedTypeVariables #-}
module Main where import Control.Applicative ((<$>), optional) import Data.Maybe (fromMaybe) import Data.Text (Text) import Data.Text.Lazy (unpack) import Happstack.Lite import Text.Blaze.Html5 (Html, (!), a, form, input, p, toHtml, label) import Text.Blaze.Html5.Attributes (action, enctype, href, name, size, type_, value) import qualified Text.Blaze.Html5 as H import qualified Text.Blaze.Html5.Attributes as A
serve
function. The first argument is the configuration; it is optional. The second argument is our web application itself. main :: IO () main = serve Nothing myApp
ServerPart Response
type. You can consider ServerPart
web equivalent of an IO
monad. myApp :: ServerPart Response myApp = msum [ dir "echo" $ echo , dir "query" $ queryParams , dir "form" $ formPage , dir "fortune" $ fortune , dir "files" $ fileServing , dir "upload" $ upload , homePage ]
dir
used so that the handler is executed only when the static components of the path are successfully matched. For example, dir "echo"
will successfully work with the address localhost:8000/echo
localhost:8000/echo
. To assign a handler to the address "/foo/bar"
, simply write dir "foo" $ dir "bar" $ handler
.Response
.msum
.homePage
, is unlimited ( dir doesn't apply to it ), so it will always be called if none of the other handlers work successfully. template :: Text -> Html -> Response template title body = toResponse $ H.html $ do H.head $ do H.title (toHtml title) H.body $ do body p $ a ! href "/" $ " "
homePage :: ServerPart Response homePage = ok $ template " " $ do H.h1 "!" Hp " Happstack Lite !" Hp " :" Hp $ a ! href "/echo/secret%20message" $ "" Hp $ a ! href "/query?foo=bar" $ " " Hp $ a ! href "/form" $ " " Hp $ a ! href "/fortune" $ "- ()" Hp $ a ! href "/files" $ " " Hp $ a ! href "/upload" $ " "
ok
function sets the page’s HTTP code “200 OK”. There are other auxiliary functions, for example, notFound
sets the code “404 Not Found”, seeOther
- “303 See Other”. To set the HTTP code number, use setResponseCode
.dir
function matches only the static part of the address. We can use the path
function to extract a value from the dynamic part of the address and optionally convert it to some type, such as Integer
. In this example, we simply display the dynamic part of the path. To check, visit http: // localhost: 8000 / echo / fantastic echo :: ServerPart Response echo = path $ \(msg :: String) -> ok $ template "" $ do p $ " : " >> toHtml msg p " , - ."
?foo=bar
". Try visiting http: // localhost: 8000 / query? Foo = bar queryParams :: ServerPart Response queryParams = do mFoo <- optional $ lookText "foo" ok $ template " " $ do p $ "foo = " >> toHtml (show mFoo) p $ " , foo."
lookText
function will return mzero
. In this example, we use optional
from the Control.Applicative
module, so we end up with a value of type Maybe
.lookText
to get data from forms. formPage :: ServerPart Response formPage = msum [ viewForm, processForm ] where viewForm :: ServerPart Response viewForm = do method GET ok $ template "form" $ form ! action "/form" ! enctype "multipart/form-data" ! A.method "POST" $ do label ! A.for "msg" $ " - " input ! type_ "text" ! A.id "msg" ! name "msg" input ! type_ "submit" ! value "" processForm :: ServerPart Response processForm = do method POST msg <- lookText "msg" ok $ template "form" $ do Hp " :" Hp (toHtml msg)
lookText
function as in the previous paragraph to get the data from the form. You may also have noticed that we use the method
function to distinguish between GET
and POST
requests./form
using GET
. In the HTML form
tag, we specified the opening of the same page as the button action, but using the attribute we chose the POST
method. fortune :: ServerPart Response fortune = msum [ viewFortune, updateFortune ] where viewFortune :: ServerPart Response viewFortune = do method GET mMemory <- optional $ lookCookieValue "- ()" let memory = fromMaybe " -!" mMemory ok $ template "fortune" $ do Hp " - ():" Hp (toHtml memory) form ! action "/fortune" ! enctype "multipart/form-data" ! A.method "POST" $ do label ! A.for "fortune" $ " : " input ! type_ "text" ! A.id "fortune" ! name "new_fortune" input ! type_ "submit" ! value "" updateFortune :: ServerPart Response updateFortune = do method POST fortune <- lookText "new_fortune" addCookies [(Session, mkCookie "fortune" (unpack fortune))] seeOther ("/fortune" :: String) (toResponse ())
( I didn't manage to save the word game between the HTTP cookie and the fortune cookie somehow - approx. Lane. )lookCookieValue
works in the same way as lookText
, with the only difference that it looks for the value in the cookies, not the query parameters or the form.addCookies
sends cookies to the browser and has the following type: addCookies :: [(CookieLife, Cookie)] -> ServerPart ()
CookieLife
determines how long cookies exist and are considered valid. Session
means the lifetime for cookies until the browser window is closed.mkCookie
takes the name of the cookie, its value, and creates a Cookie
.seeOther
(i.e., 303, redirect) tells the browser to make a new GET
request to the /fortune
page.serveDirectory
function: fileServing :: ServerPart Response fileServing = serveDirectory EnableBrowsing ["index.html"] "."
serveDirectory
create a list of files in a directory so that they can be viewed.serveDirectory
function automatically uses sendfile()
to access files. In sendfile()
low-level kernel operations are used to ensure the transfer of files from the drive to the network with minimal processor overhead and maximum utilization of the network channel.lookText
use lookFile
. upload :: ServerPart Response upload = msum [ uploadForm , handleUpload ] where uploadForm :: ServerPart Response uploadForm = do method GET ok $ template " " $ do form ! enctype "multipart/form-data" ! A.method "POST" ! action "/upload" $ do input ! type_ "file" ! name "file_upload" ! size "40" input ! type_ "submit" ! value "upload" handleUpload :: ServerPart Response handleUpload = do (tmpFile, uploadName, contentType) <- lookFile "file_upload" ok $ template " " $ do p (toHtml $ " : " ++ tmpFile) p (toHtml $ " : " ++ uploadName) p (toHtml $ " : " ++ show contentType)
moveFile
or copyFile
to move (or copy) the file to its permanent location.Source: https://habr.com/ru/post/185524/
All Articles