<?xml version="1.0" encoding="UTF-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title xmlns:ns="http://www.w3.org/2005/Atom" ns:type="text">Web frameworks – Haskell – Aelve Guide</title><id>https://guide.aelve.com/haskell/feed/category/mi360n4k</id><updated>2016-03-10T11:06:40Z</updated><link xmlns:ns="http://www.w3.org/2005/Atom" ns:href="https://guide.aelve.com/haskell/feed/category/mi360n4k"/><entry><id>o7ffrijk</id><title xmlns:ns="http://www.w3.org/2005/Atom" ns:type="text">Servant</title><updated>2016-03-10T11:06:40Z</updated><content xmlns:ns="http://www.w3.org/2005/Atom" ns:type="html">&lt;h1&gt;  &lt;a href=&#34;https://haskell-servant.github.io/&#34; class=&#34;item-name&#34;&gt;Servant&lt;/a&gt;

  
  (&lt;a href=&#34;https://hackage.haskell.org/package/servant&#34;&gt;Hackage&lt;/a&gt;)
&lt;/h1&gt;&lt;p&gt;servant is a set of Haskell libraries for writing type-safe web applications but also deriving clients (in Haskell and other languages) or generating documentation for them, and more.&lt;/p&gt;
&lt;p&gt;This is achieved by taking as input a description of the web API as a Haskell type. Servant is then able to check that your server-side request handlers indeed implement your web API faithfully, or to automatically derive Haskell functions that can hit a web application that implements this API, generate a Swagger description or code for client functions in some other languages directly.&lt;/p&gt;
&lt;h2&gt;Pros&lt;/h2&gt;&lt;ul&gt;&lt;p&gt;&lt;li&gt;Typesafe REST API.&lt;/li&gt;&lt;/p&gt;&lt;p&gt;&lt;li&gt;Provides ecosystem for integrating most web components and technologies.&lt;/li&gt;&lt;/p&gt;&lt;p&gt;&lt;li&gt;Provides auto generated, type safe client functions for querying a REST service.&lt;/li&gt;&lt;/p&gt;&lt;/ul&gt;&lt;h2&gt;Cons&lt;/h2&gt;&lt;ul&gt;&lt;p&gt;&lt;li&gt;Type errors are hideous.&lt;/li&gt;&lt;/p&gt;&lt;p&gt;&lt;li&gt;Due to the unreadable error message, it is complicated to find the actual problem.&lt;/li&gt;&lt;/p&gt;&lt;p&gt;&lt;li&gt;Uses the &lt;a href=&#34;http://www.parsonsmatt.org/2017/06/21/exceptional_servant_handling.html&#34;&gt;&lt;code&gt;ExceptT&lt;/code&gt; antipattern&lt;/a&gt;&lt;/li&gt;&lt;/p&gt;&lt;/ul&gt;&lt;h2&gt;Ecosystem&lt;/h2&gt;&lt;p&gt;The whole ecosystem is on hackage and can be found by querying for &amp;quot;servant&amp;quot;.&lt;/p&gt;
</content><link xmlns:ns="http://www.w3.org/2005/Atom" ns:href="https://guide.aelve.com/haskell/web-frameworks-mi360n4k#item-o7ffrijk"/></entry><entry><id>ida02huy</id><title xmlns:ns="http://www.w3.org/2005/Atom" ns:type="text">Yesod</title><updated>2016-03-10T11:06:40Z</updated><content xmlns:ns="http://www.w3.org/2005/Atom" ns:type="html">&lt;h1&gt;  &lt;a href=&#34;http://www.yesodweb.com/&#34; class=&#34;item-name&#34;&gt;Yesod&lt;/a&gt;

  
  (&lt;a href=&#34;https://hackage.haskell.org/package/yesod&#34;&gt;Hackage&lt;/a&gt;)
&lt;/h1&gt;&lt;p&gt;Yesod is a big, pragmatic web framework with batteries included and a huge community around it. It lets you build apps quickly and without boilerplate (but it might be unpleasant to use if you want to know exactly what&#39;s happening behind the scenes).&lt;/p&gt;
&lt;h2&gt;Pros&lt;/h2&gt;&lt;ul&gt;&lt;p&gt;&lt;li&gt;Easy to learn and to use. A lot of things are already done for you.&lt;/li&gt;&lt;/p&gt;&lt;p&gt;&lt;li&gt;Type-safe routes guarantee that your app won&#39;t have invalid links.&lt;/li&gt;&lt;/p&gt;&lt;p&gt;&lt;li&gt;Flexible widget system allows to compose UI from smaller, reusable parts.&lt;/li&gt;&lt;/p&gt;&lt;p&gt;&lt;li&gt;It&#39;s probably the fastest Haskell web framework.&lt;/li&gt;&lt;/p&gt;&lt;p&gt;&lt;li&gt;Template Haskell helps to avoid most boilerplate.&lt;/li&gt;&lt;/p&gt;&lt;/ul&gt;&lt;h2&gt;Cons&lt;/h2&gt;&lt;ul&gt;&lt;p&gt;&lt;li&gt;Yesod uses &lt;a href=&#34;https://hackage.haskell.org/package/persistent&#34;&gt;persistent&lt;/a&gt; as a database interface. It&#39;s nice, but is not powerful enough in most cases, which means you have to use &lt;a href=&#34;https://hackage.haskell.org/package/esqueleto&#34;&gt;esqueleto&lt;/a&gt; (for example, if you want to use joins). This means that you need to learn two quite different packages for database interaction.&lt;/li&gt;&lt;/p&gt;&lt;p&gt;&lt;li&gt;Template Haskell is used &lt;em&gt;a lot&lt;/em&gt; – it can be hard to understand how TH-littered code works and it doesn&#39;t look quite like Haskell. Note that &lt;em&gt;what&lt;/em&gt; the code does is usually clear – the problems begin when you try to modify it.&lt;/li&gt;&lt;/p&gt;&lt;/ul&gt;</content><link xmlns:ns="http://www.w3.org/2005/Atom" ns:href="https://guide.aelve.com/haskell/web-frameworks-mi360n4k#item-ida02huy"/></entry><entry><id>g5if8ahc</id><title xmlns:ns="http://www.w3.org/2005/Atom" ns:type="text">Snap</title><updated>2016-03-10T11:06:40Z</updated><content xmlns:ns="http://www.w3.org/2005/Atom" ns:type="html">&lt;h1&gt;  &lt;a href=&#34;http://snapframework.com/&#34; class=&#34;item-name&#34;&gt;Snap&lt;/a&gt;

  
  (&lt;a href=&#34;https://hackage.haskell.org/package/snap&#34;&gt;Hackage&lt;/a&gt;)
&lt;/h1&gt;&lt;h2&gt;Pros&lt;/h2&gt;&lt;ul&gt;&lt;/ul&gt;&lt;h2&gt;Cons&lt;/h2&gt;&lt;ul&gt;&lt;/ul&gt;</content><link xmlns:ns="http://www.w3.org/2005/Atom" ns:href="https://guide.aelve.com/haskell/web-frameworks-mi360n4k#item-g5if8ahc"/></entry><entry><id>dl3u3p9n</id><title xmlns:ns="http://www.w3.org/2005/Atom" ns:type="text">Spock</title><updated>2016-03-10T11:06:40Z</updated><content xmlns:ns="http://www.w3.org/2005/Atom" ns:type="html">&lt;h1&gt;  &lt;a href=&#34;http://spock.li&#34; class=&#34;item-name&#34;&gt;Spock&lt;/a&gt;

  
  (&lt;a href=&#34;https://hackage.haskell.org/package/Spock&#34;&gt;Hackage&lt;/a&gt;)
&lt;/h1&gt;&lt;p&gt;test&lt;/p&gt;
&lt;h2&gt;Pros&lt;/h2&gt;&lt;ul&gt;&lt;/ul&gt;&lt;h2&gt;Cons&lt;/h2&gt;&lt;ul&gt;&lt;/ul&gt;&lt;h2&gt;Notes&lt;/h2&gt;&lt;p&gt;&lt;em&gt;Examples below have been tested with Spock-0.12.&lt;/em&gt;&lt;/p&gt;
&lt;h1&gt;&lt;span id=&#34;item-notes-dl3u3p9n-a-hello-world-example&#34;&gt;&lt;/span&gt;A “hello world” example&lt;/h1&gt;&lt;div class=&#34;sourceCode&#34;&gt;&lt;pre class=&#34;sourceCode&#34;&gt;&lt;code class=&#34;sourceCode&#34;&gt;&lt;span class=&#34;ot&#34;&gt;{-# LANGUAGE OverloadedStrings #-}&lt;/span&gt;

&lt;span class=&#34;kw&#34;&gt;module&lt;/span&gt; &lt;span class=&#34;dt&#34;&gt;Main&lt;/span&gt; &lt;span class=&#34;kw&#34;&gt;where&lt;/span&gt;

&lt;span class=&#34;kw&#34;&gt;import &lt;/span&gt;&lt;span class=&#34;dt&#34;&gt;Data.Monoid&lt;/span&gt; ((&amp;lt;&amp;gt;))
&lt;span class=&#34;kw&#34;&gt;import &lt;/span&gt;&lt;span class=&#34;dt&#34;&gt;Web.Spock&lt;/span&gt;
&lt;span class=&#34;kw&#34;&gt;import &lt;/span&gt;&lt;span class=&#34;dt&#34;&gt;Web.Spock.Config&lt;/span&gt;

&lt;span class=&#34;ot&#34;&gt;main ::&lt;/span&gt; &lt;span class=&#34;dt&#34;&gt;IO&lt;/span&gt; ()
main &lt;span class=&#34;fu&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kw&#34;&gt;do&lt;/span&gt;
  config &lt;span class=&#34;ot&#34;&gt;&amp;lt;-&lt;/span&gt; defaultSpockCfg () &lt;span class=&#34;dt&#34;&gt;PCNoDatabase&lt;/span&gt; ()
  runSpock &lt;span class=&#34;dv&#34;&gt;8080&lt;/span&gt; &lt;span class=&#34;fu&#34;&gt;$&lt;/span&gt; spock config app

&lt;span class=&#34;ot&#34;&gt;app ::&lt;/span&gt; &lt;span class=&#34;dt&#34;&gt;SpockM&lt;/span&gt; () () () ()
app &lt;span class=&#34;fu&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kw&#34;&gt;do&lt;/span&gt;
  &lt;span class=&#34;co&#34;&gt;-- When “/” is requested, show “Hello world!”&lt;/span&gt;
  get root &lt;span class=&#34;fu&#34;&gt;$&lt;/span&gt;
    text &lt;span class=&#34;st&#34;&gt;&amp;quot;Hello world!&amp;quot;&lt;/span&gt;
  &lt;span class=&#34;co&#34;&gt;-- When “/hello/&amp;lt;name&amp;gt;” is requested, show “Hello &amp;lt;name&amp;gt;!”&lt;/span&gt;
  get (&lt;span class=&#34;st&#34;&gt;&amp;quot;hello&amp;quot;&lt;/span&gt; &lt;span class=&#34;fu&#34;&gt;&amp;lt;//&amp;gt;&lt;/span&gt; var) &lt;span class=&#34;fu&#34;&gt;$&lt;/span&gt; \name &lt;span class=&#34;ot&#34;&gt;-&amp;gt;&lt;/span&gt;
    text (&lt;span class=&#34;st&#34;&gt;&amp;quot;Hello &amp;quot;&lt;/span&gt; &lt;span class=&#34;fu&#34;&gt;&amp;lt;&amp;gt;&lt;/span&gt; name &lt;span class=&#34;fu&#34;&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;st&#34;&gt;&amp;quot;!&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Parts of this example are explained in detail in &lt;a href=&#34;https://www.spock.li/tutorial/&#34;&gt;the official Spock tutorial&lt;/a&gt;. In a nutshell:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;We create a Spock config with &lt;code&gt;defaultSpockCfg&lt;/code&gt;. Our session type is &lt;code&gt;()&lt;/code&gt; and our state type is &lt;code&gt;()&lt;/code&gt; as well (because we don&#39;t have any state or sessions).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;runSpock &amp;lt;port&amp;gt; . spock config&lt;/code&gt; runs a &lt;code&gt;SpockM&lt;/code&gt; action. You can register &lt;em&gt;handlers&lt;/em&gt; inside &lt;code&gt;SpockM&lt;/code&gt; – e.g. &lt;code&gt;get&lt;/code&gt; registers a handler for a GET request.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Handlers run in the &lt;code&gt;ActionT&lt;/code&gt; monad. In this monad you can do various things (this is an incomplete list):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;get the request body with &lt;code&gt;body&lt;/code&gt; or &lt;code&gt;json&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;get a query/form parameter with &lt;code&gt;param&lt;/code&gt; or &lt;code&gt;param&#39;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;add something to the response that is going to be sent back (with &lt;code&gt;text&lt;/code&gt; or &lt;code&gt;bytes&lt;/code&gt; or &lt;code&gt;html&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;set a header (e.g. content-type) with &lt;code&gt;setHeader&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;set up a redirect with &lt;code&gt;redirect&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Routes can include &lt;code&gt;var&lt;/code&gt; into them. Thanks to some type-level magic, when you include &lt;code&gt;var&lt;/code&gt; into a route, &lt;code&gt;get&lt;/code&gt;/&lt;code&gt;post&lt;/code&gt;/etc will automatically take that piece of the route and provide it to the handler as a lambda parameter. Moreover, if your handler requires e.g. &lt;code&gt;Int&lt;/code&gt;, the piece will be automatically converted to &lt;code&gt;Int&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&lt;span id=&#34;item-notes-dl3u3p9n-persistent-textbox&#34;&gt;&lt;/span&gt;Persistent textbox&lt;/h1&gt;&lt;p&gt;A more complicated example – a page with a textbox that is saved on server when you type anything into it.&lt;/p&gt;
&lt;p&gt;We&#39;re going to store our text in an &lt;code&gt;IORef&lt;/code&gt; (no databases yet, let&#39;s keep it in memory), and we&#39;ll use &lt;a href=&#34;https://hackage.haskell.org/package/lucid&#34;&gt;lucid&lt;/a&gt; for HTML generation.&lt;/p&gt;
&lt;div class=&#34;sourceCode&#34;&gt;&lt;pre class=&#34;sourceCode&#34;&gt;&lt;code class=&#34;sourceCode&#34;&gt;&lt;span class=&#34;ot&#34;&gt;{-# LANGUAGE OverloadedStrings #-}&lt;/span&gt;

&lt;span class=&#34;kw&#34;&gt;module&lt;/span&gt; &lt;span class=&#34;dt&#34;&gt;Main&lt;/span&gt; (main) &lt;span class=&#34;kw&#34;&gt;where&lt;/span&gt;

&lt;span class=&#34;co&#34;&gt;-- Monads&lt;/span&gt;
&lt;span class=&#34;kw&#34;&gt;import &lt;/span&gt;&lt;span class=&#34;dt&#34;&gt;Control.Monad.Trans&lt;/span&gt;
&lt;span class=&#34;co&#34;&gt;-- IO&lt;/span&gt;
&lt;span class=&#34;kw&#34;&gt;import &lt;/span&gt;&lt;span class=&#34;dt&#34;&gt;Data.IORef&lt;/span&gt;
&lt;span class=&#34;co&#34;&gt;-- Text&lt;/span&gt;
&lt;span class=&#34;kw&#34;&gt;import &lt;/span&gt;&lt;span class=&#34;dt&#34;&gt;Data.Text&lt;/span&gt; (&lt;span class=&#34;dt&#34;&gt;Text&lt;/span&gt;)
&lt;span class=&#34;kw&#34;&gt;import qualified&lt;/span&gt; &lt;span class=&#34;dt&#34;&gt;Data.Text.Lazy&lt;/span&gt; &lt;span class=&#34;kw&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;dt&#34;&gt;TL&lt;/span&gt;
&lt;span class=&#34;co&#34;&gt;-- Web&lt;/span&gt;
&lt;span class=&#34;kw&#34;&gt;import &lt;/span&gt;&lt;span class=&#34;dt&#34;&gt;Lucid&lt;/span&gt;
&lt;span class=&#34;kw&#34;&gt;import &lt;/span&gt;&lt;span class=&#34;dt&#34;&gt;Web.Spock&lt;/span&gt;
&lt;span class=&#34;kw&#34;&gt;import &lt;/span&gt;&lt;span class=&#34;dt&#34;&gt;Web.Spock.Config&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&#34;sourceCode&#34;&gt;&lt;pre class=&#34;sourceCode&#34;&gt;&lt;code class=&#34;sourceCode&#34;&gt;&lt;span class=&#34;co&#34;&gt;-- Take a Lucid action that generates HTML, and write that HTML to a page.&lt;/span&gt;
&lt;span class=&#34;ot&#34;&gt;lucid ::&lt;/span&gt; &lt;span class=&#34;dt&#34;&gt;MonadIO&lt;/span&gt; m &lt;span class=&#34;ot&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;dt&#34;&gt;HtmlT&lt;/span&gt; m a &lt;span class=&#34;ot&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;dt&#34;&gt;ActionT&lt;/span&gt; m a
lucid x &lt;span class=&#34;fu&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kw&#34;&gt;do&lt;/span&gt;
  rendered &lt;span class=&#34;ot&#34;&gt;&amp;lt;-&lt;/span&gt; lift (renderTextT x)
  html (TL.toStrict rendered)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&#34;sourceCode&#34;&gt;&lt;pre class=&#34;sourceCode&#34;&gt;&lt;code class=&#34;sourceCode&#34;&gt;&lt;span class=&#34;ot&#34;&gt;main ::&lt;/span&gt; &lt;span class=&#34;dt&#34;&gt;IO&lt;/span&gt; ()
main &lt;span class=&#34;fu&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kw&#34;&gt;do&lt;/span&gt;
  &lt;span class=&#34;co&#34;&gt;-- Create a variable that would hold the contents of the textbox&lt;/span&gt;
  textVar &lt;span class=&#34;ot&#34;&gt;&amp;lt;-&lt;/span&gt; newIORef (&lt;span class=&#34;st&#34;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&#34;ot&#34;&gt; ::&lt;/span&gt; &lt;span class=&#34;dt&#34;&gt;Text&lt;/span&gt;)
  &lt;span class=&#34;co&#34;&gt;-- Run the app&lt;/span&gt;
  config &lt;span class=&#34;ot&#34;&gt;&amp;lt;-&lt;/span&gt; defaultSpockCfg () &lt;span class=&#34;dt&#34;&gt;PCNoDatabase&lt;/span&gt; textVar
  runSpock &lt;span class=&#34;dv&#34;&gt;8080&lt;/span&gt; &lt;span class=&#34;fu&#34;&gt;$&lt;/span&gt; spock config app&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&#34;sourceCode&#34;&gt;&lt;pre class=&#34;sourceCode&#34;&gt;&lt;code class=&#34;sourceCode&#34;&gt;&lt;span class=&#34;ot&#34;&gt;app ::&lt;/span&gt; &lt;span class=&#34;dt&#34;&gt;SpockM&lt;/span&gt; () () (&lt;span class=&#34;dt&#34;&gt;IORef&lt;/span&gt; &lt;span class=&#34;dt&#34;&gt;Text&lt;/span&gt;) ()
app &lt;span class=&#34;fu&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kw&#34;&gt;do&lt;/span&gt;
  &lt;span class=&#34;co&#34;&gt;-- On “/store”: receive text from the POST parameter and update the variable&lt;/span&gt;
  post &lt;span class=&#34;st&#34;&gt;&amp;quot;store&amp;quot;&lt;/span&gt; &lt;span class=&#34;fu&#34;&gt;$&lt;/span&gt; &lt;span class=&#34;kw&#34;&gt;do&lt;/span&gt;
    content &lt;span class=&#34;ot&#34;&gt;&amp;lt;-&lt;/span&gt; param&#39; &lt;span class=&#34;st&#34;&gt;&amp;quot;content&amp;quot;&lt;/span&gt;
    textVar &lt;span class=&#34;ot&#34;&gt;&amp;lt;-&lt;/span&gt; getState
    liftIO &lt;span class=&#34;fu&#34;&gt;$&lt;/span&gt; writeIORef textVar content

  &lt;span class=&#34;co&#34;&gt;-- On “/”: render the main page&lt;/span&gt;
  get root &lt;span class=&#34;fu&#34;&gt;$&lt;/span&gt; lucid &lt;span class=&#34;fu&#34;&gt;$&lt;/span&gt; &lt;span class=&#34;kw&#34;&gt;do&lt;/span&gt;
    &lt;span class=&#34;co&#34;&gt;-- Include jQuery (it&#39;s overkill for a small example like this one, but&lt;/span&gt;
    &lt;span class=&#34;co&#34;&gt;-- I wanted to show how to include scripts)&lt;/span&gt;
    head_ &lt;span class=&#34;fu&#34;&gt;$&lt;/span&gt; &lt;span class=&#34;kw&#34;&gt;do&lt;/span&gt;
      script_ [src_ &lt;span class=&#34;st&#34;&gt;&amp;quot;https://code.jquery.com/jquery-2.2.2.min.js&amp;quot;&lt;/span&gt;] (&lt;span class=&#34;st&#34;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&#34;ot&#34;&gt; ::&lt;/span&gt; &lt;span class=&#34;dt&#34;&gt;Text&lt;/span&gt;)
    &lt;span class=&#34;co&#34;&gt;-- Read the text variable and render a textbox containing the text; the&lt;/span&gt;
    &lt;span class=&#34;co&#34;&gt;-- textbox has an event handler attached to it that makes a POST request&lt;/span&gt;
    &lt;span class=&#34;co&#34;&gt;-- whenever the contents of the editbox change&lt;/span&gt;
    body_ &lt;span class=&#34;fu&#34;&gt;$&lt;/span&gt; &lt;span class=&#34;kw&#34;&gt;do&lt;/span&gt;
      textVar &lt;span class=&#34;ot&#34;&gt;&amp;lt;-&lt;/span&gt; getState
      content &lt;span class=&#34;ot&#34;&gt;&amp;lt;-&lt;/span&gt; liftIO &lt;span class=&#34;fu&#34;&gt;$&lt;/span&gt; readIORef textVar
      &lt;span class=&#34;kw&#34;&gt;let&lt;/span&gt; inputHandler &lt;span class=&#34;fu&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;st&#34;&gt;&amp;quot;$.post(&#39;/store&#39;, {content: this.value})&amp;quot;&lt;/span&gt;
      textarea_ [oninput_ inputHandler] (toHtml content)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h1&gt;&lt;span id=&#34;item-notes-dl3u3p9n-sessions&#34;&gt;&lt;/span&gt;Sessions&lt;/h1&gt;&lt;p&gt;A session is just a value that the server keeps in memory for each visitor; the visitor is identified by storing a cookie in the browser.&lt;/p&gt;
&lt;p&gt;Here&#39;s a simple example that records the number of times the visitor was on the main page:&lt;/p&gt;
&lt;div class=&#34;sourceCode&#34;&gt;&lt;pre class=&#34;sourceCode&#34;&gt;&lt;code class=&#34;sourceCode&#34;&gt;&lt;span class=&#34;ot&#34;&gt;{-# LANGUAGE OverloadedStrings #-}&lt;/span&gt;

&lt;span class=&#34;kw&#34;&gt;module&lt;/span&gt; &lt;span class=&#34;dt&#34;&gt;Main&lt;/span&gt; &lt;span class=&#34;kw&#34;&gt;where&lt;/span&gt;

&lt;span class=&#34;kw&#34;&gt;import &lt;/span&gt;&lt;span class=&#34;dt&#34;&gt;Data.Monoid&lt;/span&gt;
&lt;span class=&#34;kw&#34;&gt;import &lt;/span&gt;&lt;span class=&#34;dt&#34;&gt;Web.Spock&lt;/span&gt;
&lt;span class=&#34;kw&#34;&gt;import qualified&lt;/span&gt; &lt;span class=&#34;dt&#34;&gt;Data.Text&lt;/span&gt; &lt;span class=&#34;kw&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;dt&#34;&gt;T&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&#34;sourceCode&#34;&gt;&lt;pre class=&#34;sourceCode&#34;&gt;&lt;code class=&#34;sourceCode&#34;&gt;&lt;span class=&#34;ot&#34;&gt;main ::&lt;/span&gt; &lt;span class=&#34;dt&#34;&gt;IO&lt;/span&gt; ()
main &lt;span class=&#34;fu&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kw&#34;&gt;do&lt;/span&gt;
  &lt;span class=&#34;co&#34;&gt;-- “0” will be the default session value for each new user.&lt;/span&gt;
  config &lt;span class=&#34;ot&#34;&gt;&amp;lt;-&lt;/span&gt; defaultSpockCfg &lt;span class=&#34;dv&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;dt&#34;&gt;PCNoDatabase&lt;/span&gt; ()
  runSpock &lt;span class=&#34;dv&#34;&gt;8080&lt;/span&gt; &lt;span class=&#34;fu&#34;&gt;$&lt;/span&gt; spock config app&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&#34;sourceCode&#34;&gt;&lt;pre class=&#34;sourceCode&#34;&gt;&lt;code class=&#34;sourceCode&#34;&gt;&lt;span class=&#34;ot&#34;&gt;app ::&lt;/span&gt; &lt;span class=&#34;dt&#34;&gt;SpockM&lt;/span&gt; () &lt;span class=&#34;dt&#34;&gt;Int&lt;/span&gt; () ()
app &lt;span class=&#34;fu&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kw&#34;&gt;do&lt;/span&gt;
  get root &lt;span class=&#34;fu&#34;&gt;$&lt;/span&gt; &lt;span class=&#34;kw&#34;&gt;do&lt;/span&gt;
    &lt;span class=&#34;co&#34;&gt;-- Increase the stored number and return the new number.&lt;/span&gt;
    n &lt;span class=&#34;ot&#34;&gt;&amp;lt;-&lt;/span&gt; modifyReadSession (&lt;span class=&#34;fu&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;dv&#34;&gt;1&lt;/span&gt;)
    text (&lt;span class=&#34;st&#34;&gt;&amp;quot;You visited this page &amp;quot;&lt;/span&gt; &lt;span class=&#34;fu&#34;&gt;&amp;lt;&amp;gt;&lt;/span&gt; T.pack (show n) &lt;span class=&#34;fu&#34;&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;st&#34;&gt;&amp;quot; times.&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h1&gt;&lt;span id=&#34;item-notes-dl3u3p9n-gotchas&#34;&gt;&lt;/span&gt;Gotchas&lt;/h1&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;By default Spock prints “Spock is running on port N” – if you don&#39;t want it, use &lt;code&gt;runSpockNoBanner&lt;/code&gt; instead of &lt;code&gt;runSpock&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;After you&#39;ve output anything (with &lt;code&gt;text&lt;/code&gt; or &lt;code&gt;bytes&lt;/code&gt; or something else), the action finishes. So, &lt;code&gt;text&lt;/code&gt;/&lt;code&gt;bytes&lt;/code&gt;/&lt;code&gt;html&lt;/code&gt; should be the last function you call.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content><link xmlns:ns="http://www.w3.org/2005/Atom" ns:href="https://guide.aelve.com/haskell/web-frameworks-mi360n4k#item-dl3u3p9n"/></entry><entry><id>bqenlidf</id><title xmlns:ns="http://www.w3.org/2005/Atom" ns:type="text">Scotty</title><updated>2016-03-10T11:06:40Z</updated><content xmlns:ns="http://www.w3.org/2005/Atom" ns:type="html">&lt;h1&gt;  &lt;a href=&#34;https://github.com/scotty-web/scotty&#34; class=&#34;item-name&#34;&gt;Scotty&lt;/a&gt;

  
  (&lt;a href=&#34;https://hackage.haskell.org/package/scotty&#34;&gt;Hackage&lt;/a&gt;)
&lt;/h1&gt;&lt;h2&gt;Pros&lt;/h2&gt;&lt;ul&gt;&lt;/ul&gt;&lt;h2&gt;Cons&lt;/h2&gt;&lt;ul&gt;&lt;/ul&gt;</content><link xmlns:ns="http://www.w3.org/2005/Atom" ns:href="https://guide.aelve.com/haskell/web-frameworks-mi360n4k#item-bqenlidf"/></entry></feed>