Yesod (web framework)

{{Multiple issues|

{{Primary sources|date=September 2018}}

{{how-to|date=September 2018}}

}}

{{Infobox software

| name = Yesod

| logo = Yesod Logo.svg

| screenshot =

| caption =

| author = Michael Snoyman

| developer = Michael Snoyman, et al.

| released = {{Start date and age|2010}}

| latest release version = {{wikidata|property|edit|reference|P348}}

| latest release date = {{Start date and age|{{wikidata|qualifier|P348|P577}}}}

| latest preview version =

| latest preview date =

| operating system = Cross-platform

| platform =

| language = English

| programming language = Haskell

| genre = Web framework

| license = MIT

| website = {{Official URL}}

}}

Yesod ({{IPA|he|jeˈsod}}; {{langx|he|יְסוֺד}}, "Foundation") is a web framework based on the programming language Haskell for productive development of type-safe, representational state transfer (REST) model based (where uniform resource locators (URLs) identify resources, and Hypertext Transfer Protocol (HTTP) methods identify transitions), high performance web applications, developed by Michael Snoyman, et al. It is free and open-source software released under an MIT License.

Yesod is based on templates, to generate instances for listed entities, and dynamic content process functions, through Template Haskell constructs to host domain-specific language (eDSL) content templates called QuasiQuotes, where the content is translated into code expressions by metaprogramming instructions.{{cite web |url=http://www.haskell.org/haskellwiki/Quasiquotation |title=HaskellWiki - QuasiQuotation |publisher=Haskell.org |date=2012-05-26 |access-date=2012-10-23}}

There are also web-like language snippet templates that admit code expression interpolations, making them fully type-checked at compile time.{{cite web |url=http://www.cs.kent.ac.uk/~nccb/rails-yesod-slides.pdf |title=University of Kent - Comparing Dynamic and Static Language Approaches to Web Frameworks - Yesod vs Ruby on Rails |access-date=2012-10-23}}

Yesod divides its functions in separate libraries (database, html rendering, forms, etc.) so functions may used as needed.

MVC architecture

= Controller =

== Server interface ==

Yesod uses a Web application interface (WAI),{{cite web |url=http://hackage.haskell.org/package/wai |title=The wai package |publisher=Hackage.haskell.org |access-date=2012-10-23}} a type of application programming interface (API), to isolate servlets, aka web apps., from servers, with handlers for the server protocols Common Gateway Interface (CGI),{{cite web |url=http://hackage.haskell.org/package/wai-extra |title=The wai-extra package with CGI WAI handler |publisher=Hackage.haskell.org |access-date=2012-10-23}} FastCGI,{{cite web |url=http://hackage.haskell.org/package/wai-handler-fastcgi |title=The wai-handler-fastcgi package |publisher=Hackage.haskell.org |access-date=2012-10-23}} Simple Common Gateway Interface (SCGI),{{cite web |url=http://hackage.haskell.org/package/wai-handler-scgi |title=The wai-handler-scgi package |publisher=Hackage.haskell.org |access-date=2012-10-23}} Warp,{{cite web |url=http://hackage.haskell.org/package/warp |title=The warp package |publisher=Hackage.haskell.org |access-date=2012-10-23}} Launch (open as local URL to the default browser, closing the server when the window is closed),{{cite web |url=http://hackage.haskell.org/package/wai-handler-launch |title=The wai-handler-launch package |publisher=Hackage.haskell.org |access-date=2012-10-23}}

== The ''foundation'' type ==

See ref.{{cite web |url=http://www.yesodweb.com/book/basics |title=book - Basics |publisher=Yesodweb.com |access-date=2012-10-23}} Yesod requires a data type that instantiates the model–view–controller classes. This is called the foundation type. In the example below, it is named "MyApp".

The REST model identifies a web resource with a web path. Here, REST resources are given names with an R suffix (like "HomeR") and are listed in a parseRoutes site map description template. From this list, route names and dispatch handler names are derived.

Yesod makes use of Template Haskell metaprogramming to generate code from templates at compile time, assuring that the names in the templates match and everything typechecks (e.g. web resource names and handler names).

By inserting a mkYesod call, this will call Template Haskell primitives to generate the code[http://hackage.haskell.org/package/yesod-core/docs/src/Yesod-Core-Internal-TH.html#mkYesod The mkYesod code] corresponding to the route type members, and the instances of the dispatch controller classes as to dispatch GET calls to route HomeR to a routine named composing them both as "getHomeR", expecting an existing handler that matches the name.

== Hello World ==

"Hello, World!" program example based on a Common Gateway Interface (CGI) server interface (the handler types have changed, but the philosophy remains):

{- 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|

Hello World! There are #{length params} parameters:

$if null params

Nothing to list

$else

    $forall param <- params

  • #{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

    1. 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

== Resources, routes, HTTP method handlers ==

See ref.{{cite web |url=http://www.yesodweb.com/book/routing-and-handlers |title=book - Routing and Handlers |publisher=Yesodweb.com |access-date=2012-10-23}}{{cite web |url=http://fpcomplete.com/yesod-tutorial-2-playing-with-routes-and-links/ |title=Playing with Routes and Links |publisher=FPComplete.com |date=2012-10-17 |access-date=2012-10-28}} Yesod follows the representational state transfer model of access to web documents, identifying docs. and directories as resources with a Route constructor, named with an uppercase R suffix (for example, HomeR).

;The routes table: The parseRoutes template should list the resources specifying route pieces, resource name and dispatch methods to be accepted.

URL segment capture as parameter is possible specifying a '#' prefix for single segment capture or '*' for multisegment capture, followed by the parameter type.

-- 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]

|]

  • Applying the previous template generates the following route constructors:

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}

  • For every supported HTTP method a handler function must be created to match the dispatch names generated by mkYesod from the parseRoutes template, by prefixing the method name (or the prefix "handler" if no method stated) to the resource, as described (actual versions handler types have changed, but the philosophy remains):

-- 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

== Request data, parameters, cookies, languages, other header info ==

See ref.

== Authentication, authorization ==

See ref.{{cite web |url=http://www.yesodweb.com/book/authentication-and-authorization |title=book - Authentication and Authorization |publisher=Yesodweb.com |access-date=2012-10-23}} Authentication plugins: OpenID, BrowserID, Email, GoogleEmail, HashDB, RpxNow.{{cite web |url=http://hackage.haskell.org/package/yesod-auth |title=The yesod-auth package |publisher=Hackage.haskell.org |access-date=2012-10-26}}

:There is an important setting for automatic redirection after authentication.{{cite web |url=http://www.yesodweb.com/book/sessions |title=book - Sessions - See section "Ultimate Destination"|publisher=Yesodweb.com |access-date=2012-11-17}}

== Sessions ==

See ref.{{cite web |url=http://www.yesodweb.com/book/sessions |title=Sessions |publisher=Yesodweb.com |access-date=2012-10-23}} Session back-ends: ClientSession{{cite web |url=http://hackage.haskell.org/packages/archive/clientsession/latest/doc/html/Web-ClientSession.html |title=Web.ClientSession |publisher=Hackage.haskell.org |access-date=2012-10-25}} (it stores the session in a cookie), ServerSession{{cite web |url=http://hackage.haskell.org/package/serversession |title=ServerSession: secure modular server-side sessions |publisher=Hackage.haskell.org |access-date=2018-10-29}}{{cite web |url=http://hackage.haskell.org/package/serversession-frontend-yesod |title=Web.ServerSession.Frontend.Yesod |publisher=Hackage.haskell.org |access-date=2018-10-29}} (it stores most of the session data at the server)

:>> To avoid undue bandwidth overhead, production sites can serve their static content from a separate domain name to avoid the overhead of transmitting the session cookie for each request

=== Session messages ===

A success, failure or indicative message can be stored (setMessage) in the Session and will be shown, if it exists, by the default_layout routine through the default_layout.hamlet template, being cleared on consultation.{{cite web |url=https://www.yesodweb.com/book/sessions#sessions_messages |title=Session Messages |publisher=Yesodweb.com |access-date=2018-10-23}}

== Subsites ==

Common URL prefix subsites for workflows, file serving or site partitioning. See ref.{{cite web |url=http://www.yesodweb.com/book/creating-a-subsite |title=Creating a Subsite |publisher=Yesodweb.com |access-date=2012-10-25}}{{cite web |url=http://monoid.se/haskell/yesod-and-subsites/ |title=Yesod and subsites: a no-brainer |publisher=Monoid.se |date=2012-08-22 |access-date=2012-10-28}}[]

Built-in subsites: Static,{{cite web |url=http://www.yesodweb.com/blog/2010/12/magic-of-yesod-part2 |title=The Magic of Yesod, part 2 - See section "Static Subsite" |publisher=Yesodweb.com |date=2010-12-25 |access-date=2012-10-25}}{{cite web |url=http://hackage.haskell.org/packages/archive/yesod-static/latest/doc/html/Yesod-Static.html |title=The package yesod-static - Static Subsite |publisher=Hackage.haskell.org |access-date=2012-10-25}} Auth{{cite web |url=http://hackage.haskell.org/packages/archive/yesod-auth/latest/doc/html/Yesod-Auth.html |title=The package yesod-auth - Auth Subsite |publisher=Hackage.haskell.org |access-date=2012-10-25}}

== Form processing, layout generation ==

See ref.{{cite web |url=http://www.yesodweb.com/book/forms |title=book - Forms |publisher=Yesodweb.com |access-date=2012-10-23}}

The Form type here is an object that is used in the controller to parse and process the form fields user input and produce a (FormResult, Widget) pair were the widget holds the layout of the next rendering of the form with error messages and marks. It can also be used to generate a new form with blanks or default values.

The form type takes the shape of a function of an html snippet to be embedded in the view, that will hold security purpose hidden fields.

A form object is generated from an ApplicativeMonadic composition of fields for a combined, sequential parsing of field inputs.

There are three types of forms:

  • Applicative (with tabular layout),
  • Monadic (with free layout style), both in the Yesod.Form.Functions module,
  • Input (for parsing only, no view generated) in the Yesod.Form.Input module.

The field generators, whose names are composed by the form type initial (a|m|i) followed by (req|opt){- required or optional -}, have a fieldParse component and a fieldView one.{{cite web |url=http://hackage.haskell.org/packages/archive/yesod-form/latest/doc/html/Yesod-Form-Fields.html |title=Yesod.Form.Fields |publisher=Hackage.haskell.org |access-date=2012-10-23}}

  • the function runForm{Post|Get} runs the field parsers against the form field inputs and generates a (FormResult, Widget) pair from the views offering a new form widget with the received form field values as defaults. The function suffix is the http method used in the form submission.
  • while generateForm{Post|Get} ignores inputs from the client and generates a blank or defaults form widget.{{cite web |url=http://hackage.haskell.org/packages/archive/yesod-form/latest/doc/html/Yesod-Form-Functions.html#v:runFormPost |title=Yesod.Form.Functions runFormPost |publisher=Hackage.haskell.org |access-date=2012-10-25}}

The actual function parameters and types have changed through Yesod versions. Check the Yesod book and libraries signatures.

The magic is in the {{mono|FormResult}} data type Applicative instance, where {{mono|(<*>)}} collects the error messages for the case of FormFailure [textErrMsg] result values{{cite web |url=http://hackage.haskell.org/packages/archive/yesod-form/latest/doc/html/Yesod-Form-Types.html#t:FormResult |title=Yesod.Form.Types |publisher=Hackage.haskell.org |access-date=2012-10-23}}

Monadic forms permit free form layout and better treatment of {{mono|hiddenField}} members.

A sample of an Applicative{{cite web |url=http://www.haskell.org/haskellwiki/Applicative_functor |title=HaskellWiki - Applicative functor |publisher=haskell.org |access-date=2012-10-24}} form:

-- 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

= View =

The types shown correspond to an older version, but the philosophy remains.

The Handler monad returns content in one or more of several formats as components of types that implement the {{mono|HasReps}} class{{cite web |url=http://hackage.haskell.org/packages/archive/yesod-core/latest/doc/html/Yesod-Content.html#t:HasReps |title=The class HasReps |publisher=Hackage.haskell.org |access-date=2012-10-23}} {{{mono|RepHtml, RepJson, RepXml, RepPlain}}, the dual {{mono|RepHtmlJson}}, a pair or list of pairs {{code|[(ContentType, Content)]}}, ..}.{{cite web |url=http://www.yesodweb.com/book/restful-content |title=RESTful Content |publisher=Yesodweb.com |access-date=2012-10-23}}{{cite web |url=http://hackage.haskell.org/packages/archive/yesod-core/latest/doc/html/Yesod-Content.html#t:ToContent |title=The class ToContent |publisher=Hackage.haskell.org |access-date=2012-10-23}} Json examples:{{cite web |url=http://www.yesodweb.com/blog/2012/04/yesod-js-todo |title=More Client Side Yesod: todo sample |publisher=Yesodweb.com |date=2012-04-23 |access-date=2012-10-23}}{{cite web |url=http://www.yesodweb.com/book/json-web-service |title=JSON Web Service |publisher=Yesodweb.com |access-date=2012-10-23}}{{cite web |url=http://hackage.haskell.org/package/yesod-json |title=The yesod-json package |publisher=Hackage.haskell.org |access-date=2012-10-23}}

The {{mono|HasReps}} default implementation of {{mono|chooseRep}} chooses the document representation to be returned according to the preferred content-type list of the client {{mono|accept}} header.

  • Widgets{{cite web |url=http://www.yesodweb.com/book/widgets |title=book - Widgets |publisher=Yesodweb.com |access-date=2012-10-23}} are HTML DOM code snippets made by specific commands (e.g. setTitle) or from templates of structure (HTML) / behaviour (JavaScript) / style (CSS), whose types instantiate the classes ToWidget, ToWidgetHead or ToWidgetBody.

A Widget monad,{{cite web |url=http://hackage.haskell.org/packages/archive/yesod-core/latest/doc/html/Yesod-Widget.html#t:GWidget |title=The widget monad |publisher=Hackage.haskell.org |access-date=2012-10-23}} based on a Writer{{cite web |url=http://www.haskell.org/haskellwiki/All_About_Monads#The_Writer_monad |title=The Writer monad |publisher=Haskell.org |access-date=2012-10-23}} one and argument to {{mono|defaultLayout}}, facilitate to piece the widgets together.

== Indentation based templates for tree structured markup ==

  • the {{mono|hamlet}} quasiquoter (a parser to compile-time Template Haskell code){{cite web |url=http://www.haskell.org/ghc/docs/latest/html/users_guide/template-haskell.html#th-quasiquotation |title=Template Haskell Quasi-quotation |publisher=Haskell.org |access-date=2012-11-02}} specified in the T.H. Oxford brackets syntax [qq| ... |] introduces an indentation based structured html template. (See doc.).{{cite web |url=https://hackage.haskell.org/package/shakespeare/docs/Text-Hamlet.html |title=The hamlet template module |publisher=Hackage.haskell.org |access-date=2012-10-23}}

'$' prefixes lines of logic statements.

Automatic closing tags are generated only for the tag at line start position.

  • the {{mono|whamlet}} quasiquoter returns a Widget expression. (saves to Widget before [hamlet|..|]).

toWidget [hamlet|

$doctype 5

#{pageTitle} - My Site</p> <p><link rel=stylesheet href=@{Stylesheet_route}></p> <p><body></p> <p><header></p> <p>^{headerTemplate}</p> <p><section #mySectionId></p> <p><p><span .titleClass>_{MsgArticleListTitle}</span></p> <p>$if null articles</p> <p><p :isRed:style="color:red">_{MsgSorryNoArticles}</p> <p>$else</p> <p><ul></p> <p>$forall art <- articles</p> <p><li>#{articleNumber art} .- #{articleTitle art}</p> <p><footer></p> <p>^{footerTemplate}</p> <p>|]</p> <p></syntaxhighlight></p></div></section><section class='wiki-section collapsible' id='section--emplate-interpolation-hakespearean-templates-'><h2 class='section-toggle'>=== Template interpolation - ''Shakespearean templates'' ===</h2><div class='wiki-body'><p>See ref.<ref name="book-shakesp-templates">{{cite web |url=http://www.yesodweb.com/book/shakespearean-templates |title=book - Shakesperean templates |publisher=Yesodweb.com |access-date=2012-10-23}}</ref></p> <p>These are content view templates that follow a common substitution pattern of code expressions within curly brackets with different character prefix to refer to</p> <p>; template expressions with <code>^{...}</code>: refers to other templates of the same type, with given parameters as <code>^{template params}</code>,</p> <p>; route expressions with <code>@{...}</code>: safe (typed) urls as <code>@{HomeR}</code>,</p> <p>; message expressions with <code>_{...}</code>: <a href='?title=i18n'>i18n</a> message rendering as <code>_{MsgMessageLabel params}</code></p> <p>; other Haskell expressions with <code>#{...}</code>: haskell expression rendering as <code>#{haskell_expression}</code> which type must be convertible</p> <ul> <li>in case of <em><a href='?title=%23HTML-like_templates'>hamlet</a></em> html templates, the expression type must be an instance of Text.Blaze.ToMarkup<ref>{{cite web |url=http://hackage.haskell.org/packages/archive/blaze-markup/latest/doc/html/Text-Blaze.html#t:ToMarkup |title=Class Text.Blaze.ToMarkup |publisher=Hackage.haskell.org |access-date=2012-10-23}}</ref></li> <li>in case of <a href='?title=CSS'>CSS</a> templates, the expression type must be an instance of Text.Cassius.ToCss<ref>{{cite web |url=http://hackage.haskell.org/packages/archive/shakespeare/latest/doc/html/Text-Cassius.html#t:ToCss |title=Class Text.Cassius.ToCss |publisher=Hackage.haskell.org |access-date=2012-10-23}}</ref></li> <li>in case of <a href='?title=JavaScript'>JavaScript</a> templates, the expression type must be an instance of Text.Julius.ToJavascript <ref>{{cite web |url=http://hackage.haskell.org/packages/archive/shakespeare/latest/doc/html/Text-Julius.html#t:ToJavascript |title=Class Text.Julius.ToJavascript |publisher=Hackage.haskell.org |access-date=2012-10-23}}</ref></li> <li>in case of <a href='?title=i18n'>i18n</a> message definitions (in "<code><isoLanguage></code>.msg" files) with parameter interpolations, the expression type must be an instance of Text.Shakespeare.I18N.ToMessage <ref>{{cite web |url=http://hackage.haskell.org/packages/archive/shakespeare/latest/doc/html/Text-Shakespeare-I18N.html#t:ToMessage |title=Class Text.Shakespeare.I18N.ToMessage |publisher=Hackage.haskell.org |access-date=2012-10-24}}</ref></li> <li>in case of text/plain templates (for use in emails), the expression type must be an instance of Text.Shakespeare.Text.ToText <ref>{{cite web |url=http://hackage.haskell.org/packages/archive/shakespeare/latest/doc/html/Text-Shakespeare-Text.html#t:ToText |title=Class Text.Shakespeare.Text.ToText |publisher=Hackage.haskell.org |access-date=2012-10-24}}</ref></li> </ul> <p>Using non-English text in expressions requires use of the <a href='?title=Unicode'>Unicode</a>-aware type {{mono|Text}}, since the <a href='?title=Glasgow_Haskell_Compiler'>Glasgow Haskell Compiler</a>'s (GHC's) {{mono|show}} for the type {{mono|String}} renders non-<a href='?title=ASCII'>ASCII</a> characters as escaped numerical codes.</p> <p>; External file templates:</p> <ul> <li>at compile time: Template content can be loaded from external files using compile time {{mono|splice}} calls as <em>$(expr)</em>.<ref name="th">{{cite web |url=http://www.haskell.org/ghc/docs/latest/html/users_guide/template-haskell.html |title=Template Haskell |publisher=haskell.org |access-date=2012-11-03}}</ref></li> <li>at run time: There is a <em>reload mode</em> for reparsing external template files at every service call, except for HTML {{mono|hamlet}} templates: See doc.<ref>{{cite web |url=https://www.yesodweb.com/book/shakespearean-templates#shakespearean-templates_calling_shakespeare |title=book - Shakesperean templates # Calling shakespeare |publisher=Yesodweb.com |access-date=2012-10-23}}</ref></li> </ul></div></section><section class='wiki-section collapsible' id='section--ther-templates-'><h2 class='section-toggle'>=== Other templates ===</h2><div class='wiki-body'><p>; for JavaScript, CoffeeScript, Roy: the {{mono|julius}} quasiquoter: introduces a JavaScript template.<ref name="shakespeare-js">{{cite web |url=https://hackage.haskell.org/package/shakespeare/docs/Text-Julius.html |title=The Julius template module |publisher=Hackage.haskell.org |access-date=2012-10-23}}</ref> JavaScript variants <a href='?title=CoffeeScript'>CoffeeScript</a> and Roy-language<ref>{{cite web |url=http://roy.brianmckenna.org/ |title=Roy language |publisher=Roy.brianmckenna.org |access-date=2012-10-23}}</ref> have also specific {{mono|quasiquoters}}.<ref name="haskell-qq"/><ref name="shakespeare-js"/></p> <p>;for CSS:</p> <ul> <li>the {{mono|cassius}} quasiquoter: introduces a css template with indentation based structuring.<ref name="shakespeare-css">{{cite web |url=https://hackage.haskell.org/package/shakespeare/docs/Text-Cassius.html |title=The Cassius template module |publisher=Hackage.haskell.org |access-date=2012-10-23}}</ref></li> <li>the {{mono|lucius}} quasiquoter: introduces a css template with standard syntax plus shakespeare-template style substitutions.<ref>{{cite web |url=https://hackage.haskell.org/package/shakespeare/docs/Text-Lucius.html |title=The Lucius template module |publisher=Hackage.haskell.org |access-date=2012-10-23}}</ref></li> </ul> <p>; <a href='?title=TypeScript'>TypeScript</a> and <a href='?title=React_%28JavaScript_library%29%23JSX'>JSX</a> templates: the {{mono|tsc}} and {{mono|tscJSX}} quasiquoters. Only on <a href='?title=UNIX'>UNIX</a> derivatives (no <a href='?title=Windows'>Windows</a> by now).<ref>{{cite web |url=https://hackage.haskell.org/package/shakespeare/docs/Text-TypeScript.html |title=The Typescript template module |publisher=Hackage.haskell.org |access-date=2018-10-10}}</ref></p> <p>; text/plain templates: for <a href='?title=e-mail'>e-mail</a> or <em>text/plain</em> <a href='?title=http'>http</a> <a href='?title=content_type'>content type</a>.<ref name="shakespeare-text">{{cite web |url=https://hackage.haskell.org/package/shakespeare/docs/Text-Shakespeare-Text.html |title=Shakespeare plain text templates module |publisher=Hackage.haskell.org |access-date=2012-10-24}}</ref></p> <ol> <li>templates: {{mono|lt}}: lazy text, {{mono|st}}: strict text</li> <li>templates for text with a left margin delimiter '|': {{mono|lbt}} (lazy), {{mono|sbt}} (strict)</li> </ol></div></section><section class='wiki-section collapsible' id='section--ocalizable-messages-'><h2 class='section-toggle'>== Localizable messages ==</h2><div class='wiki-body'><p>See ref.<ref>{{cite web |url=http://www.yesodweb.com/book/internationalization |title=book - Internationalization |publisher=Yesodweb.com |access-date=2012-10-23}}</ref></p> <p>Yesod app messages are localizable (<a href='?title=i18n'>i18n</a>). They should be held within the {{mono|messages}} folder, in files named based on <a href='?title=International_Organization_for_Standardization'>ISO</a>, as <em><iso-language>.msg</em></p> <p>Message entries follow the <a href='?title=Extended_Backus%E2%80%93Naur_form'>EBNF</a> pattern:</p> <p><syntaxhighlight lang="hs"></p> <p>-- EBNF: identifier, {' ', parameter, '@', type}, ":", text with interpolations</p> <p>ArticleUnexistent param@Int64 : unexistent article #{param}</p> <p></syntaxhighlight></p> <ul> <li>message constructors are formed prepending "Msg" to the message label identifier.</li> <li>the message datatype is formed appending "Message" to the foundation type name.</li> </ul> <p><syntaxhighlight lang="hs"></p> <p>-- in code</p> <p>myMsg :: MyAppMessage -- datatype appending "Message" to the foundation type</p> <p>myMsg = MsgArticleUnexistent myArticleId -- constructor prepending "Msg" to the msg. label</p> <p>-- in widget templates</p> <p>_{MsgArticleUnexistent myArticleId}</p> <p></syntaxhighlight></p> <p>Actual <a href='?title=i18n'>i18n</a> support is missing from the {{mono|stack}} app template. The <code>mkMessage "MyApp" messagesFolder isoLangDefault</code> must be added to the "Foundation.hs" file to get the messages instantiated.<ref>[https://hackage.haskell.org/package/shakespeare/docs/Text-Shakespeare-I18N.html#v:mkMessage mkMessage]</ref></p></div></section><section class='wiki-section collapsible' id='section--avigation-breadcrumbs-'><h2 class='section-toggle'>== Navigation breadcrumbs ==</h2><div class='wiki-body'><ul> <li>Navigation <a href='?title=Breadcrumb_navigation'>breadcrumbs</a>.<ref name="breadcrumbs">{{cite web |url=http://hackage.haskell.org/packages/archive/yesod-core/latest/doc/html/Yesod-Core.html#t:YesodBreadcrumbs |title=The YesodBreadcrumbs class |publisher=Hackage.haskell.org |access-date=2012-11-05}}</ref> A YesodBreadcrumbs instance must be provided for the site where the generator function {{mono|breadcrumb}} should return for each route a title and parent one. Then, the query function {{mono|breadcrumbs}} will return the present route title and the ancestors' (route, title) pairs.</li> </ul></div></section><section class='wiki-section collapsible' id='section--earch-engine-itemap-'><h2 class='section-toggle'>== Search engine XML Sitemap ==</h2><div class='wiki-body'><ul> <li>Search engines <a href='?title=Sitemap%23XML_Sitemaps'>XML Sitemaps</a>,<ref>{{cite web |url=http://hackage.haskell.org/package/yesod-sitemap |title=The yesod-sitemap package |publisher=Hackage.haskell.org |access-date=2012-10-26}}</ref> where {{mono|sitemap}} returns an XML Sitemap as <a href='?title=http'>http</a> response, with the routes we want the search engines to crawl, and attributes to instruct the crawler, from a provided list of {{mono|SitemapUrl}} records.</li> </ul></div></section><section class='wiki-section collapsible' id='section--eb-feed-views-'><h2 class='section-toggle'>== Web feed views ==</h2><div class='wiki-body'><ul> <li><a href='?title=Web_feed'>Web feed</a> views (<a href='?title=RDF_Site_Summary'>RDF Site Summary</a> (RSS) – <a href='?title=Atom_%28standard%29'>Atom</a>).<ref>{{cite web |url=http://hackage.haskell.org/package/yesod-newsfeed |title=The yesod-newsfeed package for RSS / Atom views |publisher=Hackage.haskell.org |access-date=2012-10-26}}</ref> Handlers return {{mono|RepRss, RepAtom}}, or dual {{mono|RepAtomRss}} content (to be selected on {{mono|accept}} headers' preferred content-type list) from a given {{mono|Feed}} structure.</li> </ul></div></section><section class='wiki-section collapsible' id='section--odel-'><h2 class='section-toggle'>= Model =</h2><div class='wiki-body'></div></section><section class='wiki-section collapsible' id='section--sing-in-memory-mutable-data-in-the-foundation-datatype-'><h2 class='section-toggle'>== Using in-memory mutable data (in the foundation datatype) ==</h2><div class='wiki-body'><p>E.g. a visitor count. See ref.<ref>{{cite web |url=http://www.yesodweb.com/book/initializing-foundation-data |title=Book - Initializing data in the foundation datatype |publisher=Yesodweb.com |access-date=2014-05-26}}</ref></p></div></section><section class='wiki-section collapsible' id='section--he-atabase-layer-'><h2 class='section-toggle'>== The Database layer ==</h2><div class='wiki-body'><ul> <li><em>persistent</em> is the name of the database access layer with templates for generating types for entities and keys as well as schema initialization.<ref name="book-persistent">{{cite web |url=http://www.yesodweb.com/book/persistent |title=book - Persistent |publisher=Yesodweb.com |access-date=2012-10-23}}</ref><ref>{{cite web |url=http://hackage.haskell.org/package/yesod-persistent |title=Yesod-persistent package |publisher=Hackage.haskell.org |access-date=2012-10-23}}</ref><ref>{{cite web |url=https://github.com/yesodweb/persistent/tree/master/docs |title=Yesod-persistent docs |publisher=github.com |access-date=2018-10-16}}</ref></li> </ul> <p>There is first class support for <a href='?title=PostgreSQL'>PostgreSQL</a>, <a href='?title=SQLite'>SQLite</a>, <a href='?title=MongoDB'>MongoDB</a>, <a href='?title=CouchDB'>CouchDB</a> and <a href='?title=MySQL'>MySQL</a>, with experimental support for <a href='?title=Redis'>Redis</a>.<ref name="book-persistent"/></p> <p>The Database layout is described in a template listing the entities, fields and constraints.<ref>{{cite web |url=https://github.com/yesodweb/persistent/blob/master/docs/Persistent-entity-syntax.md |title=Yesod-persistent entity syntax |publisher=github.com |access-date=2018-10-16}}</ref></p> <ul> <li>For every entity listed, an integer key column "id" is generated with autoincrement and primary index attributes, with a type alias appending Id to the entity name</li> <li>For every entity listed, a record type named as the entity is generated were record fields names are composed prefixing the entity name to the field name like "personName". An EntityField type "PersonName" is also generated for foreign key referencing from other entities.</li> <li>There is an automatic <em>database schema migration</em> mechanism for DB schema updates, which, to succeed, requires, when adding columns to existent tables, to specify 'Default-column-value constraints<em> with </em>sql level notation''.<ref>{{cite web |url=https://github.com/yesodweb/yesod/issues/401 |title=Redundant migrations for fields' default values|publisher=GitHub.com |access-date=2012-12-04}}</ref></li> <li>"At most one" cardinality has a special mechanism around the type Checkmark.<ref>{{cite web |url=http://hackage.haskell.org/package/persistent/docs/Database-Persist-Types.html#t:Checkmark |title="At most one" cardinality enforcement in <em>persistent</em> with type Checkmark|publisher=Hackage.haskell.org |access-date=2018-10-16}}</ref></li> <li>Weak entities (childs in life constrained owner-child relationships) have no special support for cascade delete <em>triggers</em>, but there are functions to <em>deleteCascade</em> manually in the Database.Persist.Class module.<ref>{{cite web |url=https://stackoverflow.com/questions/24369045/how-can-i-create-a-foreign-key-constraint-using-yesod-persistent/24379218#24379218 |title=How can I create a foreign key constraint using Yesod/Persistent?|publisher=stackoverflow.com |access-date=2018-10-16}}</ref></li> </ul> <p>; automatic table creation, schema update and table migration: Modifications of the entities template produces an schema update with automatic table creation, and migration for the <a href='?title=Database_management_system'>DBMS</a>'s that support "ALTER TABLE" <a href='?title=SQL'>SQL</a> commands in a <em>migrateAll</em> procedure, generated from the template content. See "Migrations" in ref.<ref name="book-persistent"/> to look for migration aware <a href='?title=Database_management_system'>DBMS</a>.</p> <p><syntaxhighlight lang="hs"></p> <p>share [mkPersist sqlSettings,</p> <p>mkMigrate "migrateAll" -- generates the migration procedure with the specified name</p> <p>] [persist|</p> <p>User -- table name and entity record type</p> <p>-- implicit autoincrement column "id" as primary key, typed UserId</p> <p>ident Text -- refers to db. table column "ident";</p> <p>-- generates a record field prefixing the table name as "userIdent"</p> <p>password Text Maybe -- Maybe indicates Nullable field</p> <p>UniqueUser ident -- unique constraint with space sep. field sequence</p> <p>Email -- table name and entity record type</p> <p>-- implicit autoincrement column "id" as primary key, typed EmailId</p> <p>email Text</p> <p>user UserId -- foreign key by specifying other tables EntityField types</p> <p>verkey Text Maybe</p> <p>newlyAddedColumn Text "default='sometext'::character varying" -- sql level Default constraint</p> <p>UniqueEmail email -- unique constraint</p> <p>|]</p> <p></syntaxhighlight></p> <ul> <li>Esqueleto: is a haskell combinators layer to generate correct relational queries to <em>persistent</em>.<ref>{{cite web |url=http://hackage.haskell.org/package/esqueleto |title=esqueleto package |publisher=Hackage.haskell.org |access-date=2012-10-23}}</ref></li> </ul> <p>Example for <em>persistent rawSQL</em> and <em>Esqueleto</em> queries.<ref>{{cite web |url=https://stackoverflow.com/questions/9047636/baffled-by-selectonemany-in-yesod/12483493#12483493 |title=Query example at |publisher=Stackoverflow.com |date=2012-09-19 |access-date=2012-10-23}}</ref></p></div></section><section class='wiki-section collapsible' id='section--mail-'><h2 class='section-toggle'>= E-mail =</h2><div class='wiki-body'><p>The following packages are part of the <em>yesod-platform</em>:<ref name="yesod-platform">{{cite web |url=http://hackage.haskell.org/package/yesod |title=The yesod package |publisher=Hackage.haskell.org |access-date=2019-06-26}}</ref></p> <ul> <li>email-validate: Validating an email address.<ref>{{cite web |url=http://hackage.haskell.org/package/email-validate |title=The email-validate package |publisher=Hackage.haskell.org |access-date=2012-10-26}}</ref></li> <li>mime-mail: Compose and send <a href='?title=MIME'>MIME</a> email messages.<ref>{{cite web |url=http://hackage.haskell.org/package/mime-mail |title=The mime-mail package. |publisher=Hackage.haskell.org |access-date=2012-10-26}}</ref></li> </ul></div></section><section class='wiki-section collapsible' id='section--acebook-'><h2 class='section-toggle'>= Facebook =</h2><div class='wiki-body'><ul> <li>Useful glue functions between the fb library and Yesod.<ref>{{cite web |url=http://hackage.haskell.org/package/yesod-fb |title=The yesod-fb package. |publisher=Hackage.haskell.org |access-date=2012-10-26}}</ref></li> </ul></div></section><section class='wiki-section collapsible' id='section--evelopment-cycle'><h2 class='section-toggle'>Development cycle</h2><div class='wiki-body'><p>New Yesod apps are generated from the HaskellStack tool<ref>[https://docs.haskellstack.org/en/stable/README/#how-to-install Haskell Stack - How to install]</ref> templates, replacing previous command "yesod init"</p> <p><em>Stack</em> based app. template names are prefixed by yesod as "yesod-{minimal | postgres | sqlite | mysql | mongo | ...}"</p> <ul> <li>Since HaskellStack uses the <em>stackage</em> repo by default, extra packages from the <em>hackage</em> repo should be referred in the "stack.yaml" <em>extra-deps</em> section.</li> <li>Packages may be customized to a local subfolder. They must be referred in the "stack.yaml" <em>packages</em> section.</li> </ul></div></section><section class='wiki-section collapsible' id='section--he-esod-helper-tool-'><h2 class='section-toggle'>= The "Yesod helper" tool =</h2><div class='wiki-body'><ul> <li>The <em>yesod</em> helper tool <ref>[https://hackage.haskell.org/package/yesod-bin#readme The yesod-bin pkg with the helper tool (with instructions for use with the <em>stack</em> tool)]</ref></li> <li><code>yesod devel</code> run from the project site, recompiles and restarts the project at every file tree modification.</li> <li><code>yesod add-handler</code> adds a new handler and module to the project, adding an <em>import</em> clause for the handler in the "Application" module.</li> </ul></div></section><section class='wiki-section collapsible' id='section--eploying-with-eter-web-app-server-monitor-and-reverse-proxy-server-'><h2 class='section-toggle'>= Deploying with Keter: A web app server monitor and reverse proxy server =</h2><div class='wiki-body'><p>See refs.<ref name="book-deploying">{{cite web |url=http://www.yesodweb.com/book/deploying-your-webapp |title=book - Deploying your Webapp |publisher=Yesodweb.com |access-date=2012-10-23}}</ref><ref>{{cite web|author=Readme.Md |url=https://github.com/snoyberg/keter#readme |title=Yesod keter readme |publisher=GitHub |access-date=2012-10-23}}</ref></p> <p><ref>{{cite web |url=http://hackage.haskell.org/package/keter |title=The keter package |publisher=Hackage.haskell.org |access-date=2012-10-23}}</ref></p> <p>Keter is a process as a service that handles deployment and restart of Yesod <a href='?title=web_app'>web app</a> servers, and, per <em><a href='?title=web_app'>web app</a></em>, database creation for <a href='?title=PostgreSQL'>PostgreSQL</a>.</p> <p>The console command <code>yesod keter</code> packs the web app. as a keter bundle for uploading to a keter folder named "incoming".</p> <p>Keter monitors the "incoming" folder and unpacks the app. to a temporary one, then assigns the web app a port to listen to, and starts it.</p> <p>Initially it worked with <a href='?title=Nginx'>Nginx</a> as <a href='?title=reverse_proxy'>reverse proxy</a> (keter version 0.1*), adding <a href='?title=Virtual_hosting'>virtual server</a> entries to its configuration and making <a href='?title=Nginx'>Nginx</a> reload it, but now Keter itself provides its own <em><a href='?title=reverse_proxy'>reverse proxy</a></em> functionality, removing Nginx dependency and acting as the main web server.<ref>{{cite web |url=http://www.yesodweb.com/blog/2012/10/keter-updates |title=Keter updates |publisher=Yesodweb.com |date=2012-10-25 |access-date=2012-10-25}}</ref></p> <p>Old documentation (Nginx based).<ref>{{cite web |url=http://www.yesodweb.com/blog/2012/05/keter-app-deployment |title=Keter: Web App Deployment |publisher=Yesodweb.com |date=2012-05-11 |access-date=2012-10-23}}</ref><ref>{{cite web |url=http://www.yesodweb.com/blog/2012/05/keter-its-alive |title=Keter: It's Alive! |publisher=Yesodweb.com |date=2012-05-17 |access-date=2012-10-23}}</ref></p></div></section><section class='wiki-section collapsible' id='section--ntegration-with-ava-cript-generated-from-functional-languages'><h2 class='section-toggle'>Integration with [[JavaScript]] generated from functional languages</h2><div class='wiki-body'><p>See ref.<ref>{{cite web |url=https://github.com/yesodweb/yesod/wiki/Javascript-Options |title=Javascript Options |publisher=github.com |access-date=2014-03-12}}</ref><ref>{{cite web |url=http://www.yesodweb.com/blog/2012/10/yesod-fay-js |title=Yesod, AngularJS and Fay |publisher=yesodweb.com |date=2012-10-30 |access-date=2014-03-12}}</ref><ref name="the-js-problem">{{cite web |url=http://www.haskell.org/haskellwiki/The_JavaScript_Problem |title=HaskellWiki - The JavaScript Problem |publisher=haskell.org |access-date=2014-04-12}}</ref></p></div></section><section class='wiki-section collapsible' id='section--ee-also'><h2 class='section-toggle'>See also</h2><div class='wiki-body'><p>{{Portal|Free and open-source software}}</p> <ul> <li><a href='?title=Snap_%28web_framework%29'>Snap (web framework)</a></li> </ul></div></section><section class='wiki-section collapsible' id='section--eferences'><h2 class='section-toggle'>References</h2><div class='wiki-body'><p>{{Reflist|2}}</p></div></section><section class='wiki-section collapsible' id='section--xternal-links'><h2 class='section-toggle'>External links</h2><div class='wiki-body'><ul> <li>{{Official website}}</li> <li>Presentations: [http://www.infoq.com/presentations/Yesod InfoQ], [https://skillsmatter.com/skillscasts/3521-scalable-web-applications-with-yesod Haskell eXchange 2012]</li> <li>Slides: [http://www.acm.jhu.edu/~nwf/fwh/08_yesod.pdf A.C.M. at Johns Hopkins University - ReST-ful Websites with Yesod]</li> <li>ScreenCast: [http://vimeo.com/39646807 Yesod 1.0 at Vimeo]</li> <li>[http://shop.oreilly.com/product/0636920023142.do O'Reilly ebook - Developing Web Applications with Haskell and Yesod - Safety-Driven Web Development]</li> <li>Q&A: [https://stackoverflow.com/questions/tagged/yesod StackOverflow.com - Yesod tagged Q&A]</li> </ul></div></section><section class='wiki-section collapsible' id='section--log-tutorials-'><h2 class='section-toggle'>= Blog tutorials =</h2><div class='wiki-body'><ul> <li>[http://fpcomplete.com/yesod-tutorial-1-my-first-web-site/ FPComplete.com - My First Web Site], [http://fpcomplete.com/yesod-tutorial-2-playing-with-routes-and-links/ Playing with Routes and Links]</li> <li>[http://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/ Yesod for newbies]</li> <li>[http://hamberg.no/erlend/posts/2012-08-23-handlertoio-yesod.html hamberg.no - handlerToIO: use forkIO in Yesod handlers]</li> </ul></div></section><section class='wiki-section collapsible' id='section--omparisons-'><h2 class='section-toggle'>= Comparisons =</h2><div class='wiki-body'><ul> <li>[http://www.haskell.org/haskellwiki/Web/Frameworks HaskellWiki - Haskell web frameworks]</li> <li>[http://softwaresimply.blogspot.com.es/2012/04/hopefully-fair-and-useful-comparison-of.html A Hopefully Fair and Useful Comparison of Haskell Web Frameworks]</li> <li>[http://www.cs.kent.ac.uk/~nccb/rails-yesod-slides.pdf University of Kent - Comparing Dynamic and Static Language Approaches to Web Frameworks - Yesod vs Ruby on Rails]</li> </ul></div></section><section class='wiki-section collapsible' id='section--ther-languages-'><h2 class='section-toggle'>= Other languages =</h2><div class='wiki-body'><ul> <li>[http://wikis.uca.es/wikihaskell/index.php/Biblioteca_Yesod Haskell Biblio. - Yesod] {{in lang|es}} University of <a href='?title=Cadiz'>Cadiz</a></li> </ul></div></section><section class='wiki-section collapsible' id='section--t-inux-distributions-'><h2 class='section-toggle'>= At Linux distributions =</h2><div class='wiki-body'><ul> <li>[http://packages.debian.org/search?keywords=yesod&searchon=names§ion=all Yesod at Debian]</li> <li>[https://packages.ubuntu.com/search?keywords=yesod&searchon=names&suite=hirsute§ion=all Yesod at Ubuntu]</li> </ul> <p>{{Web frameworks}}</p> <p>{{Haskell programming}}</p> <p><a href='?title=Category%3AWeb_frameworks'>Category:Web frameworks</a></p> <p><a href='?title=Category%3AFree_software_programmed_in_Haskell'>Category:Free software programmed in Haskell</a></p> <p><a href='?title=Category%3A2010_software'>Category:2010 software</a></p> <p><!-- Hidden categories below --></p> <p><a href='?title=Category%3AArticles_with_example_Haskell_code'>Category:Articles with example Haskell code</a></p></div></section></div></main> <footer class="site-footer"> <div class="footer-container"> <div class="footer-links"> <a href="/about.php">About</a> <a href="/help.php">Help</a> <a href="/updates.php">Updates</a> <a href="/contact.php">Contact</a> <a href="/privacy.php">Privacy</a> <a href="/terms.php">Terms</a> <a href="https://github.com/yourusername/friendly-wiki" target="_blank" rel="noopener">GitHub</a> </div> <div class="footer-copy"> © 2025 Friendly Wiki. All rights reserved. </div> </div> </footer> <script> const toggle = document.getElementById('mobileMenuToggle'); const menu = document.getElementById('mobileMenu'); toggle.addEventListener('click', () => { menu.classList.toggle('active'); }); </script> <!-- Collapsible toggle --> <script> document.addEventListener("DOMContentLoaded", function () { const toggles = document.querySelectorAll('.section-toggle'); toggles.forEach(toggle => { toggle.addEventListener('click', function () { const section = toggle.closest('.collapsible'); const body = section.querySelector('.wiki-body'); body.classList.toggle('collapsed'); }); }); }); </script>