Yesod web 框架/控制器
Yesod 使用 Web 應用程式介面 API,[1] 簡稱 WAI,將 servlet(即 web 應用程式)與伺服器隔離開,併為伺服器協議 CGI,[2] FastCGI,[3] SCGI,[4] Warp,[5] Launch(將本地 URL 開啟到預設瀏覽器,在視窗關閉時關閉伺服器)[6] 提供處理程式。
參見 ref.[7] Yesod 需要一個數據型別來例項化控制器類。這稱為 基礎 型別。在下面的示例中,它名為 "MyApp"。
REST 模型透過 Web 路徑標識 Web 資源。這裡,REST 資源使用帶有 R 字尾的名稱(例如 "HomeR")來命名,並在 parseRoutes 站點地圖描述模板中列出。從這個列表中,派生路由名稱和排程處理程式名稱。
Yesod 利用模板 Haskell 超程式設計在編譯時從模板生成程式碼,確保模板中的名稱匹配並且所有內容都經過型別檢查(例如,Web 資源名稱和處理程式名稱)。
透過插入 mkYesod 呼叫,這將呼叫模板 Haskell 原語來生成與路由型別成員相對應的程式碼[8],以及排程控制器類的例項,以便將 GET 呼叫排程到路由 HomeR 到一個名為將兩者組合起來作為 "getHomeR" 的例程,期望一個與名稱匹配的現有處理程式。
"Hello world" 示例基於 CGI 伺服器介面(實際處理程式型別已經改變,但理念保持不變)
{- file wai-cgi-hello.hs -}
{-# LANGUAGE PackageImports, TypeFamilies, QuasiQuotes, MultiParamTypeClasses,
TemplateHaskell, OverloadedStrings #-}
import "wai" Network.Wai
import "wai-extra" Network.Wai.Handler.CGI (run) -- interchangeable WAI handler
import "yesod" Yesod
import "yesod-core" Yesod.Handler (getRequest)
import "text" Data.Text (Text)
import "shakespeare" Text.Cassius (Color(..), colorBlack)
-- the Foundation type
data MyApp = MyApp
-- sitemap template, listing path, resource name and methods accepted
-- `mkYesod` takes the foundation type name as param. for name composition of dispatch functions
mkYesod "MyApp" [parseRoutes|
/ HomeR GET
|]
instance Yesod MyApp
-- indentation structured CSS template
myStyle :: [Text] → CssUrl url
myStyle paramStyle =
[cassius|
.box
border: 1px solid #{boxColor}
|]
where
boxColor = case paramStyle of
["high-contrast"] → colorBlack
_ → Color 0 0 255
-- indentation structured HTML template
myHtml :: [(Text, Text)] → HtmlUrl url
myHtml params = [hamlet|
<!-- indentation, or lack of it, under starting tags or commands ('$' prefix)
describe the content or sequence tree structure -->
<!-- '.' or '#' prefixes in tags introduce css styled "class" or "id" attribute values -->
<!-- interpolation of haskell expressions follow the "shakespeare templates" #{expr} syntax -->
<p>Hello World! There are <span .box>#{length params} parameters</span>:
$if null params
<p>Nothing to list
$else
<ul>
$forall param <- params
<li>#{fst param}: #{snd param}
|]
getHomeR :: Handler RepHtml
getHomeR = do
req <- getRequest
let params = reqGetParams req
paramStyle <- lookupGetParams "style"
defaultLayout $ do
-- adding widgets to the Widget monad (a ''Writer'' monad)
setTitle "Yesod example"
toWidgetHead $ myStyle paramStyle
toWidgetBody $ myHtml params
-- there are ''run'' function variants for different WAI handlers
main = toWaiApp MyApp >>= run
# cgi test
export REMOTE_ADDR=127.0.0.1
export REQUEST_METHOD=GET
export PATH_INFO=/
export QUERY_STRING='p1=abc;p2=def;style=high-contrast'
./wai-cgi-hello
參見 ref.[9][10] Yesod 遵循訪問 Web 文件的 REpresentational State Transfer 模型,使用路由建構函式識別文件和目錄作為資源,並使用大寫 R 字尾命名(例如,HomeR)。
- 路由表
- parseRoutes 模板應列出指定路由片段、資源名稱和要接受的排程方法的資源。
URL 段捕獲作為引數是可能的,指定 '#' 字首用於單段捕獲,或 '*' 用於多段捕獲,後跟引數型別。
-- given a MyApp foundation type
mkYesod "MyApp" [parseRoutes|
/ HomeR -- no http methods stated: all methods accepted
/blog BlogR GET POST
-- the '#' prefix specify the path segment as a route handler parameter
/article/#ArticleId ArticleR GET PUT
-- the '*' prefix specify the parameter as a sequence of path pieces
/branch/*Texts BranchR GET
-- to simplify the grammar, compound types must use an alias, eg. type Texts for ''[Text]''
|]
- 應用前面的模板生成以下路由建構函式
data Route MyApp =
HomeR -- referenced in templates as: @{HomeR}
| BlogR -- in templates: @{BlogR}
| ArticleR ArticleId -- in templates: @{ArticleR myArticleId}
| BranchR Texts -- in templates: @{BranchR myBranchSegments}
- 對於每種支援的 HTTP 方法,必須建立一個處理程式函式來匹配 mkYesod 從 parseRoutes 模板生成的排程名稱,方法是將方法名稱(如果未指定方法,則使用字首 "handler")附加到資源,如所描述的那樣(實際版本處理程式型別已經改變,但理念保持不變)
-- for "/ HomeR" -- no http methods stated ⇒ only one handler with prefix ''handler''
handlerHomeR :: HasReps t ⇒ Handler t
-- for "/blog BlogR GET POST"
getBlogR :: HasReps t ⇒ Handler t
postBlogR :: HasReps t ⇒ Handler t
-- for "/article/#ArticleId ArticleR GET PUT"
getArticleR :: HasReps t ⇒ ArticleId → Handler t
putArticleR :: HasReps t ⇒ ArticleId → Handler t
參見 ref.[9]
參見 ref.[11] 身份驗證外掛:OpenId、BrowserId、電子郵件、Google 電子郵件、HashDB、RpxNow.[12]
- 身份驗證後自動重定向有一個重要的設定。[13]
參見 ref.[14] 會話後端:ClientSession[15](它將會話儲存在 Cookie 中)、ServerSession[16][17](它將大部分會話資料儲存在伺服器上)
- >> 為了避免不必要的頻寬開銷,生產站點可以從一個單獨的域名提供靜態內容,以避免為每個請求傳輸會話 Cookie 的開銷。
可以在會話中儲存成功、失敗或指示性訊息(setMessage),如果存在,則透過 default_layout.hamlet 模板,由 default_layout 例程顯示,並在諮詢時清除。[18]
用於工作流、檔案服務或站點分割槽之類的通用 URL 字首子站點。參見 ref.[19][20]
內建子站點:Static,[21][22] Auth[23]
參見 ref.[24]
這裡的 Form 型別是一個物件,它在 controller 中使用,用於解析和處理表單欄位使用者輸入,並生成一個 (FormResult, Widget) 對,其中小部件包含表單的下一個渲染的佈局,包括錯誤訊息和標記。它還可用於生成帶有空白或預設值的新表單。
表單型別採用一個要嵌入到檢視中的 html 片段的函式的形式,該片段將包含出於安全目的的隱藏欄位。
表單物件是從欄位的 Applicative/Monadic 組合生成的,用於對欄位輸入進行組合/順序解析。
有三種類型的表單
- Applicative(帶有表格佈局),
- Monadic(帶有自由佈局樣式),兩者都在 Yesod.Form.Functions 模組中,
- Input(僅用於解析,不生成檢視)位於 Yesod.Form.Input 模組中。
欄位生成器,其名稱由表單型別初始 (a|m|i) 後跟 (req|opt){- 必需或可選 -} 組成,具有一個 fieldParse 元件和一個 fieldView 元件。[25]
- 函式 runForm{Post|Get} 會對錶單欄位輸入執行欄位解析器,並從檢視中生成一個 (FormResult, Widget) 對,提供一個新的表單小部件,其中接收到的表單欄位值作為預設值。函式字尾是表單提交中使用的 HTTP 方法。
- 而 generateForm{Post|Get} 會忽略來自客戶端的輸入,並生成一個空白或預設表單小部件。[26]
實際的函式引數和型別在 Yesod 版本中有所改變。請檢視 Yesod 手冊和庫簽名。
神奇之處在於 FormResult 資料型別 Applicative 例項,其中 (<*>) 收集了 FormFailure [textErrMsg] 結果值的錯誤訊息。[27]
單子形式允許自由的表單佈局和對 hiddenField 成員的更好處理。[24]
一個 Applicative[28] 表單的示例
-- a record for our form fields
data Person = Person {personName :: Text, personAge :: Int, personLikings :: Maybe Text}
-- the Form type has an extra parameter for an html snippet to be embedded, containing a CSRF token hidden field for security
type Form sub master x = Html → MForm sub master (FormResult x, Widget)
{-
-- for messages in validation functions:
@param master: yesod instance to use in renderMessage (return from handler's getYesod)
@param languages: page languages to use in renderMessage
-- optional defaults record:
@param mbPersonDefaults: Just defaults_record, or Nothing for blank form
-}
personForm :: MyFoundationType → [Text] → Maybe Person → Form sub master Person
{- ''aopt'' (optional field AForm component) for "Maybe" fields,
''areq'' (required fld AForm comp.) will insert the "required" attribute
-}
personForm master languages mbPersonDefaults = renderTable $
Person <$> areq textField fldSettingsName mbNameDefault
<*> areq customPersonAgeField fldSettingsAge mbAgeDefault
<*> aopt textareaField fldSettingsLikings mbLikingsDefault
where
mbNameDefault = fmap personName mbPersonDefaults
mbAgeDefault = fmap personAge mbPersonDefaults
mbLikingsDefault = fmap personLikings mbPersonDefaults
-- "fieldSettingsLabel" returns an initial fieldSettings record
-- recently the "FieldSettings" record can be defined from a String label since it implements IsString
fldSettingsName = (fieldSettingsLabel MsgName) {fsAttrs = [("maxlength","20")]}
fldSettingsAge = fieldSettingsLabel MsgAge
fldSettingsLikings = (fieldSettingsLabel MsgLikings) {fsAttrs = [("cols","40"),("rows","10")]}
customPersonAgeField = check validateAge intField
validateAge y
| y < 18 = Left $ renderMessage master languages MsgUnderAge
| otherwise = Right y
| 本頁部分內容基於以下材料 維基百科: 免費的百科全書. |
- ↑ "The wai package". Hackage.haskell.org. Retrieved 2012-10-23.
- ↑ "The wai-extra package with CGI WAI handler". Hackage.haskell.org. Retrieved 2012-10-23.
- ↑ "The wai-handler-fastcgi package". Hackage.haskell.org. Retrieved 2012-10-23.
- ↑ "The wai-handler-scgi package". Hackage.haskell.org. Retrieved 2012-10-23.
- ↑ "The warp package". Hackage.haskell.org. Retrieved 2012-10-23.
- ↑ "The wai-handler-launch package". Hackage.haskell.org. Retrieved 2012-10-23.
- ↑ a b "book - Basics". Yesodweb.com. Retrieved 2012-10-23.
- ↑ The mkYesod code
- ↑ a b "book - Routing and Handlers". Yesodweb.com. Retrieved 2012-10-23.
- ↑ "Playing with Routes and Links". FPComplete.com. 2012-10-17. Retrieved 2012-10-28.
- ↑ "book - Authentication and Authorization". Yesodweb.com. Retrieved 2012-10-23.
- ↑ "The yesod-auth package". Hackage.haskell.org. Retrieved 2012-10-26.
- ↑ "book - Sessions - See section "Ultimate Destination"". Yesodweb.com. Retrieved 2012-11-17.
- ↑ "Sessions". Yesodweb.com. Retrieved 2012-10-23.
- ↑ "Web.ClientSession". Hackage.haskell.org. Retrieved 2012-10-25.
- ↑ "ServerSession: secure modular server-side sessions". Hackage.haskell.org. Retrieved 2018-10-29.
- ↑ "Web.ServerSession.Frontend.Yesod". Hackage.haskell.org. Retrieved 2018-10-29.
- ↑ "Session Messages". Yesodweb.com. Retrieved 2018-10-23.
- ↑ "建立子站點". Yesodweb.com. Retrieved 2012-10-25.
- ↑ "Yesod 和子站點:輕而易舉". Monoid.se. 2012-08-22. Retrieved 2012-10-28.[]
- ↑ "Yesod 的魔力,第二部分 - 請參見“靜態子站點”部分". Yesodweb.com. 2010-12-25. Retrieved 2012-10-25.
- ↑ "yesod-static 包 - 靜態子站點". Hackage.haskell.org. Retrieved 2012-10-25.
- ↑ "yesod-auth 包 - 認證子站點". Hackage.haskell.org. Retrieved 2012-10-25.
- ↑ a b "書籍 - 表單". Yesodweb.com. Retrieved 2012-10-23.
- ↑ "Yesod.Form.Fields". Hackage.haskell.org. Retrieved 2012-10-23.
- ↑ "Yesod.Form.Functions runFormPost". Hackage.haskell.org. Retrieved 2012-10-25.
- ↑ "Yesod.Form.Types". Hackage.haskell.org. Retrieved 2012-10-23.
- ↑ "HaskellWiki - 可應用函子". haskell.org. Retrieved 2012-10-24.