Jump to content

Yesod (web framework)

From Wikipedia, the free encyclopedia

This is an old revision of this page, as edited by Michel.SLM (talk | contribs) at 06:36, 17 October 2012 (spelling corrections). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.

Yesod
Original author(s)Michael Snoyman
Developer(s)Michael Snoyman et al.
Initial release2010
Stable release
1.1.3[1] / September 26, 2012 (2012-09-26)
Repository
Written inHaskell
Operating systemCross-platform
Available inHaskell
TypeWeb application framework
LicenseMIT
Websiteyesodweb.com

Yesod, a word that comes from the Hebrew language, with stress on sod, is a free web application framework based on Haskell for productive development of type-safe, RESTful, high performance web applications, developed by Michael Snoyman et al.

Yesod is based on templates, to generate data instances for several entities, and dynamic content process functions, making use of Haskell Quasiquotation[2] to check and compile the templates, making it fully statically typed.[3]

Controller

server interface

Yesod uses a Web application interface API[4], abbrev. wai, to isolate servlets, aka web apps., from servers, with handlers for CGI,[5] FastCGI,[6] SCGI,[7] Warp,[8] Launch (open as local URL to the default browser, closing the server when the window is closed),[9] ..

WAI CGI Hello World

{- file wai-cgi-hello.hs -}
{-# LANGUAGE PackageImports, OverloadedStrings #-}
import "wai" Network.Wai
import "http-types" Network.HTTP.Types.Status
import "wai-extra" Network.Wai.Handler.CGI (run)  -- interchangeable WAI handler
import "conduit" Data.Conduit (ResourceT)
import "bytestring" Data.ByteString.Lazy (fromChunks)
import qualified "text" Data.Text.Encoding as TE

-- wai type Application = Request -> ResourceT IO Response

myapp :: Application          
myapp req = do
  -- LBS is for lazy ByteString
  return $ responseLBS ok200 [("Content-type", "text/plain")] content
 where
  content = fromChunks [TE.encodeUtf8 "Hello World\n"]
  
main = run myapp
export REMOTE_ADDR=127.0.0.1
export REQUEST_METHOD=GET
export PATH_INFO=/
./wai-cgi-hello

Resources, Routes and HTTP method handlers

Yesod follows the REpresentational State Transfer model of access to web documents, identifying docs. and directories as resources, named with an uppercase R suffix (for example, HomeR).

The parseRoutes template should list the resources specifying route pieces, resource name and dispatch methods.[10]

[parseRoutes|
/ HomeR GET POST

/article/#ArticleId ArticleR GET PUT
|]

For every dispatch method a handler function must be created by prefixing the method name to the resource, to match the generated dispatch names, as described:

-- / HomeR GET POST
getHomeR :: Handler RepHtml
postHomeR :: Handler RepHtml

-- /article/#ArticleId ArticleR GET PUT
getArticleR :: ArticleId -> Handler RepHtml
putArticleR :: ArticleId -> Handler RepHtml

Model

  • persistent is the name of the database access layer with templates for generating an entity type for each table.[11][12]

There is first class support for PostgreSQL, SQLite and MongoDB, with experimental support for CouchDB and MySQL.[11]

[persist|
User                            -- table name and entity record type
                 -- implied autoincrement column "id" as primary key, typed UserId
    ident Text                  -- record field "userIdent" (prefixing the entity name)
    password Text Maybe         -- Maybe: Nullable field
    UniqueUser ident            -- unique constraint with comma sep. field list

Email
    email Text
    user UserId                 -- foreign key
    verkey Text Maybe
    UniqueEmail email
|]
  • Esqueleto: is a haskell combinators layer to generate correct relational queries to persistent.[13]

Persistent rawSQL and Esqueleto query example.[14]

Forms

There are Applicative, Monadic and Input (non rendering, input only) kinds of forms. [15]

View

Content is defined in composable yesod widgets[16] which are code elements that can be generated from html/javascript/css w3c doc. pieces, and combined within a WriterT monad transformer.[17]

shakespearean templates

See ref.[18] These are content view templates that follow a common substitution pattern to refer to

  • other templates of the same type as ^{template_expression},
  • safe urls as @{route_expression},
  • haskell expression rendering as #{showable_haskell_expression}
  • i18n message rendering _{MsgMessage params}

localizable (i18n) messages

See ref.[19] For every supported language ISO name there should be a file in the messages subfolder as en.msg with entries as

ArticleUnexistant id@Int64: unexistant article #{id}

each one of them generates a msg constructor prefixed by "Msg", so the example msg. can be referred as

-- in code
myMsg = MsgArticleUnexistant myArticleId 
     
-- in templates
  _{MsgArticleUnexistant myArticleId}   

HTML Templates

  • hamlet templates.[20]
toWidget [hamlet|
$doctype 5
<html>
    <head>
        <title>#{pageTitle} - My Site
        <link rel=stylesheet href=@{Stylesheet_route}>
    <body>
        <div>
           ^{headerTemplate}
        <div>
          <p>_{MsgArticleListTitle}
          $if null articles
            <p>_{MsgEmptyList}
          $else
            <ul>
                $forall art <- articles
                    <li>#{articleNumber art} .- #{articleTitle art}
        <div>
          ^{footerHamletTemplate}
|]

Javascript Templates

  • julius: a javascript template.[21]
toWidgetHead [julius|

var myfunc = function(){document.location = "@{SomeRouteR}";}

^{extraJuliusTemplate}
|]

CSS Templates

  • lucius: a css template with standard syntax plus shakespeare-template style substitutions.[22]
toWidgetHead [lucius|
.box { border: 1px solid #{myColor} ;
       background-image: url(@{MyImageR}) ;
     } 

^{extraLuciusTemplate}
|]
  • cassius: a css template with indentation based structuring.[22]
toWidget [cassius|
.box
    border: 1px solid #{myColor}
    background-image: url(@{MyImageR})

^{extraCassiusTemplate}
|]

Getting started

Create a sandboxed cabal-dev repository for yesod and yesod projects.

mkdir yesod && cd yesod
cabal-dev install yesod
export PATH=$PWD/cabal-dev/bin:$PATH

Scaffolding

The console command yesod init after asking for details, generates a starting scaffold application in a subfolder with the project name. Then cd to the project folder.

Create a link to the parent dir. cabal-dev folder (if you want to use the same library repository) and build the project

ln -s ../cabal-dev cabal-dev
cabal-dev install

Configuration environments

  • Development, Testing, Staging, Production

You may launch your server project with one of theese environments described as configuration property sets in the config files settings.yml and <yourDBMS>.yml that permit specifying different base url as approot, port, and other config. as well as different database names, and other db parameters adjustable for the purposes of the specific environment.

You have to add the preferred config. environment as argument to your project task.

# launch the server with the ''Testing'' configuration environment.
# cabal-dev installs executables at ./cabal-dev/bin
my_project Testing   

Developing

The console command yesod --dev devel (the --dev flag is to look for cabal-dev library repo.) compiles the project in the current folder and starts it as a web server, but also listens for file modifications in the project directory tree, and recompiles it every time you save a yesod component, whether haskell code or template file.

Deploying

See ref.[23] There is somewhat automatic deploy handling for the Nginx web server through a yesod server daemon process called keter.[24]

>> Keter handles deployment of web apps, providing a reverse proxy to achieve zero downtime deployments.[25]

The console command yesod keter packs the web app. project for uploading. A keter process monitors an incoming folder and deploys the web app. in a similar way as the Tomcat Java server deploys servlets.

With Apache it can be run as a reverse proxy as Warp or as a FastCGI/CGI Apache handler.

References