Yesod (web framework)


Yesod is a web framework based on the programming language Haskell for productive development of type-safe, representational state transfer model based identify resources, and Hypertext Transfer Protocol, 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 content templates called QuasiQuotes, where the content is translated into code expressions by metaprogramming instructions.
There are also web-like language snippet templates that admit code expression interpolations, making them fully type-checked at compile time.
Yesod divides its functions in separate libraries so functions may used as needed.

MVC architecture

Yesod uses the model–view–controller software design pattern for its user interfaces.

Controller

Server interface

Yesod uses a Web application interface, a type of application programming interface, to isolate servlets, aka web apps., from servers, with handlers for the server protocols Common Gateway Interface, FastCGI, Simple Common Gateway Interface, Warp, Launch,

The ''foundation'' type

See ref. 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 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.
By inserting a mkYesod call, this will call Template Haskell primitives to generate the 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

example based on a Common Gateway Interface server interface :

import "wai" Network.Wai
import "wai-extra" Network.Wai.Handler.CGI -- interchangeable WAI handler
import "yesod" Yesod
import "yesod-core" Yesod.Handler
import "text" Data.Text
import "shakespeare" Text.Cassius
-- 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" → CssUrl url
myStyle paramStyle =
→ colorBlack
_ → Color 0 0 255
-- indentation structured HTML template
myHtml :: → HtmlUrl url
myHtml params =


Hello World! There are # parameters:
$if null params

Nothing to list
$else


    $forall param <- params
  • #: #


    getHomeR :: Handler RepHtml
    getHomeR = do
    req <- getRequest
    let params = reqGetParams req
    paramStyle <- lookupGetParams "style"

    defaultLayout $ do
    -- adding widgets to the Widget 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. 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.
    ;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"

    • Applying the previous template generates the following route constructors:

    data Route MyApp =
    HomeR -- referenced in templates as: @
    | BlogR -- in templates: @
    | ArticleR ArticleId -- in templates: @
    | BranchR Texts -- in templates: @

    • 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 to the resource, as described :

    -- 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. Authentication plugins: OpenID, BrowserID, Email, GoogleEmail, HashDB, RpxNow.

    Sessions

    See ref. Session back-ends: ClientSession, ServerSession
    Session messages
    A success, failure or indicative message can be stored 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.

    Subsites

    Common URL prefix subsites for workflows, file serving or site partitioning. See ref.
    Built-in subsites: Static, Auth

    Form processing, layout generation

    See ref.
    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 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,
    • Monadic, both in the Yesod.Form.Functions module,
    • Input in the Yesod.Form.Input module.
    The field generators, whose names are composed by the form type initial followed by , have a fieldParse component and a fieldView one.
    • the function runForm runs the field parsers against the form field inputs and generates a 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 ignores inputs from the client and generates a blank or defaults form widget.
    The actual function parameters and types have changed through Yesod versions. Check the Yesod book and libraries signatures.
    The magic is in the data type Applicative instance, where collects the error messages for the case of FormFailure result values
    Monadic forms permit free form layout and better treatment of members.
    A sample of an Applicative form:

    -- a record for our form fields
    data Person = Person
    -- 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
    personForm :: MyFoundationType → → Maybe Person → Form sub master Person
    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 =
    fldSettingsAge = fieldSettingsLabel MsgAge
    fldSettingsLikings =
    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 class. Json examples:
    The default implementation of chooses the document representation to be returned according to the preferred content-type list of the client header.
    • Widgets are HTML DOM code snippets made by specific commands or from templates of structure / behaviour / style, whose types instantiate the classes ToWidget, ToWidgetHead or ToWidgetBody.
    A Widget monad, based on a Writer one and argument to, facilitate to piece the widgets together.