Yesod (; , "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.
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 (database, html rendering, forms, etc.) so functions may used as needed.
MVC architecture
(MVC)
Controller
Server interface
Yesod uses a Web application interface (WAI), 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), FastCGI, Simple Common Gateway Interface (SCGI), Warp, Launch (open as local URL to the default browser, closing the server when the window is closed),
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 (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 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|
<!-- 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