scratch/output/Scratch/en/blog/Yesod-tutorial-for-newbies/index.html

514 lines
21 KiB
HTML
Raw Normal View History

2011-12-29 16:05:05 +00:00
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="fr" xml:lang="fr">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="keywords" content="yesod, haskell, programming, web">
<link rel="shortcut icon" type="image/x-icon" href="/Scratch/img/favicon.ico" />
<link rel="stylesheet" type="text/css" href="/Scratch/assets/css/main.css" />
<link rel="stylesheet" type="text/css" href="/Scratch/css/twilight.css" />
<link rel="stylesheet" type="text/css" href="/Scratch/css/idc.css" />
<link rel="alternate" type="application/rss+xml" title="RSS" href="http://feeds.feedburner.com/yannespositocomen"/>
<link rel="alternate" lang="fr" xml:lang="fr" title="Tutoriel Yesod pour les nuls" type="text/html" hreflang="fr" href="/Scratch/fr/blog/Yesod-tutorial-for-newbies/" />
<link rel="alternate" lang="en" xml:lang="en" title="Yesod tutorial for newbies" type="text/html" hreflang="en" href="/Scratch/en/blog/Yesod-tutorial-for-newbies/" />
<script type="text/javascript" src="/Scratch/js/jquery-1.3.1.min.js"></script>
<script type="text/javascript" src="/Scratch/js/jquery.cookie.js"></script>
<script type="text/javascript" src="/Scratch/js/index.js"></script>
<!--[if lt IE 9]>
<script src="http://ie7-js.googlecode.com/svn/version/2.1(beta4)/IE9.js"></script>
<![endif]-->
<title>Yesod tutorial for newbies</title>
</head>
<body lang="en" class="article">
<script type="text/javascript">// <![CDATA[
document.write('<div id="blackpage"><img src="/Scratch/img/loading.gif" alt="loading..."/></div>');
// ]]>
</script>
<div id="content">
<div id="choix">
<div class="return"><a href="#entete">&darr; Menu &darr;</a></div>
<div id="choixlang">
<a href="/Scratch/fr/blog/Yesod-tutorial-for-newbies/" onclick="setLanguage('fr')">en Français</a>
</div>
<div class="flush"></div>
</div>
<div id="titre">
<h1>
Yesod tutorial for newbies
</h1>
</div>
<div class="flush"></div>
<div class="flush"></div>
<div id="afterheader">
<div class="corps">
<p><img alt="Title image" src="/Scratch/img/blog/Yesod-tutorial-for-newbies/warp-benchmark.png" /></p>
<div class="intro">
<p><span class="sc"><abbr title="Too long; didn't read">tl;dr</abbr>: </span> A simple yesod tutorial. You shouldnt need to know Haskell very well. </p>
<blockquote>
<ul id="markdown-toc">
<li><a href="#install">Install</a></li>
<li><a href="#initialization">Initialization</a></li>
<li><a href="#configure-git">Configure git</a></li>
<li><a href="#a-last-point">A last point</a></li>
<li><a href="#protected-echo">Protected echo</a></li>
2011-12-30 16:14:57 +00:00
<li><a href="#cleaning-up">Cleaning up</a> <ul>
<li><a href="#separate-handlers">Separate handlers</a></li>
<li><a href="#use-datatext-instead-of-string">Use <code>Data.Text</code> instead of <code>String</code></a></li>
<li><a href="#use-a-new-template-file">Use a new template file</a></li>
</ul>
</li>
2011-12-29 16:05:05 +00:00
<li><a href="#protected-input">Protected input</a></li>
</ul>
</blockquote>
</div>
<p>You want the best technology to handle your new web application?
Me too. After searching a lot, it appears if you focus only on technical aspect, Haskell is the way to go.</p>
<p>It is <a href="http://www.yesodweb.com/blog/2011/03/preliminary-warp-cross-language-benchmarks">extremely fast</a>.
It is secure by nature. Many typical programming bug are hard to make in Haskell.
Haskell is also a “high level of abstraction” language. You can organize your code clearly.</p>
<p>Actually there are three web frameworks in Haskell:</p>
<ol>
<li><a href="http://happstack.com">Happstack</a></li>
<li><a href="http://snapframework.com">Snap</a></li>
<li><a href="http://yesodweb.com">Yesod</a></li>
</ol>
<p>It is very hard to choose between these three.
But my feeling goes to Yesod.
It appears to be the one with most part done for you.
As a beginner, lets stay away of the detail as most as possible.</p>
<p>The following tutorial contains some parts.</p>
<ul>
<li>Install → Install haskell and yesod. This can be long, but it is all automatic and this should be straightforward.</li>
<li>Initialization → Initialize the project and configure it.</li>
<li>Configure git → This is not mandatory, but it is a good practice.</li>
<li>Verify the security → A first step to verify the yesod framework protect us from most common errors.</li>
<li>Create a minimal blog → This is the “hello world” of web framework.</li>
<li>Some tuning → Use html5 boilerplate for example.</li>
</ul>
<h2 id="install">Install</h2>
<p>First you need to install <a href="http://www.haskell.org">Haskell</a>. The recommended way to do this is to use the <a href="http://www.haskell.org/platform">Haskell Platform</a>.</p>
<p>Secondly you need to install yesod.</p>
<pre class="twilight">
<span class="Keyword">&gt;</span> cabal update
<span class="Keyword">&gt;</span> cabal install yesod cabal-dev
</pre>
<p>That is all. It should take some time to
do this as cabal will download all
package and then compile them.</p>
<h2 id="initialization">Initialization</h2>
<p>Open a terminal and:</p>
<pre class="twilight">
<span class="Keyword">&gt;</span> yesod init
</pre>
2011-12-30 16:14:57 +00:00
<p>I entered my name, the name of the project was <code>yosog</code> and the name of the Foundation was <code>Yosog</code>, then I chosen <code>sqlite</code>.</p>
2011-12-29 16:05:05 +00:00
<p>Perfect. Now you can start the development cycle:</p>
<pre class="twilight">
<span class="Keyword">&gt;</span> cd yosog
<span class="Keyword">&gt;</span> cabal-dev install <span class="Keyword">&amp;&amp;</span> yesod --dev devel
</pre>
<p>This will compile the entire project.
In the end you should now be able to see your local website by clicking this link:</p>
<p><a href="http://localhost:3000"><code>http://localhost:3000</code></a></p>
<p>Congratulation! You were able to see your yesod powered website.
For the rest of the tutorial, use another terminal and let this one open in a corner to see what occurs.</p>
<h2 id="configure-git">Configure git</h2>
<p>It is not mandatory for a tutorial, but it is a good practice to have a CVS.</p>
<p>To use <code>git</code> copy this <code>.gitignore</code> file into the <code>yosog</code> folder.</p>
<div class="code"><div class="file"><a href="/Scratch/en/blog/Yesod-tutorial-for-newbies/code/.gitignore"> &#x27A5; .gitignore </a></div><div class="withfile">
<pre class="twilight">
cabal-dev
dist
.static-cache
static/tmp
*.sqlite3
</pre>
</div></div>
<p>Then initialize your git repository:</p>
<pre class="twilight">
<span class="Keyword">&gt;</span> git init .
<span class="Keyword">&gt;</span> git add .
<span class="Keyword">&gt;</span> git commit -a -m <span class="String"><span class="String">&quot;</span>Initial yesod commit<span class="String">&quot;</span></span>
</pre>
<p>Now we are ready to modify our web application.</p>
<h2 id="a-last-point">A last point</h2>
<p>What did we done:</p>
<ol>
<li>We have a directory containing a bunch of files</li>
<li>We have a local web server on port 3000</li>
</ol>
<p>If we modify a file inside this directory, yesod should try
to recompile as fast as possible the site. This way, you should
see the modification you done.</p>
<p>Instead of explaining the role of every file,
lets get straight to the point.</p>
<p>Inside the <code>yosog</code> the important files/directories for this tutorial are:</p>
<ol>
<li><code>config/routes</code></li>
<li><code>Handler/</code></li>
<li><code>templates/</code></li>
<li><code>static/</code></li>
<li><code>config/models</code></li>
</ol>
<p>Obviously:</p>
<ul>
<li><code>config/routes</code> is where youll configure the map URL → Code.</li>
<li><code>Handler/</code> contains the files that will contain the code called when a URL is accessed.</li>
<li><code>templates/</code> contains HTML, JS and CSS templates. </li>
<li><code>static/</code> contains static files.</li>
<li><code>config/models</code> is where youll configure the persistent objects (database tables).</li>
</ul>
<p>With these informations we should be able to do a lot.
Also note until here we dont even typed any line of Haskell.</p>
<h2 id="protected-echo">Protected echo</h2>
<p>To verify the quality of the security of the yesod framework, lets look at a minimal echo application.</p>
<p>Our goal:</p>
2011-12-30 16:14:57 +00:00
<p>Accessing <a href="http://localhost:3000/echo/some%20text"><code>http://localhost:3000/echo/some%20text</code></a>, should display “some text” in an %html web page.</p>
2011-12-29 16:05:05 +00:00
<p>Lets take a look at the file <code>config/routes</code>:</p>
<pre class="twilight">
/static StaticR Static getStatic
/auth AuthR Auth getAuth
/favicon.ico FaviconR GET
/robots.txt RobotsR GET
/ RootR GET
</pre>
<p>We want to add a route of the form <code>/echo/[anything]</code> somehow and do some action with this.
We add the following:</p>
<pre>
/echo/#String EchoR GET
</pre>
<p>This line contains three elements: the <span class="sc">url</span> pattern, a handler name, an HTTP method.
I am not particularly fan of the big R in the end of handler names.
But this is the standard convention, then I use it.</p>
<p>If you save <code>config/routes</code>, you should see your terminal in which you launched <code>yesod devel</code> do things.
And certainly break in error.</p>
<pre>
Application.hs:31:1: Not in scope: `getEchoR'
</pre>
<p>Why? Simply because we didnt written the code for the handler <code>EchoR</code>.
Now, lets do this. Edit the file <code>Handler/Root.hs</code> and append this:</p>
<pre class="twilight">
<span class="Entity">getEchoR</span>&nbsp;:: <span class="Constant">String</span> &rarr; <span class="Constant">Handler</span> <span class="Constant">RepHtml</span>
getEchoR theText = <span class="Keyword">do</span>
defaultLayout $ <span class="Keyword">do</span>
[whamlet|&lt;h1&gt;#{theText}|]
</pre>
<p>After saving the file, you should see yesod recompile the application.
When the compilation is finished youll see the message: <code>Starting devel application</code>.
You can now visit: <a href="http://localhost:3000/echo/Yesod%20rocks!"><code>http://localhost:3000/echo/Yesod%20rocks!</code></a></p>
<p>TADA! It works.</p>
<p>Now, lets try to attack our website by entering name with special characters:</p>
2011-12-30 16:14:57 +00:00
<p><a href="http://localhost:3000/echo/&lt;a&gt;I'm &lt;script&gt;alert(&quot;Bad!&quot;);"><code>http://localhost:3000/echo/&lt;a&gt;I'm &lt;script&gt;alert("Bad!");</code></a></p>
2011-12-29 16:05:05 +00:00
<p>The special characters are protected for us.
If you have a malicious user, he could not hide some bad script inside his name for example.</p>
<p>This is a direct consequence of <em>type safety</em>.
The URL string is put inside a URL type.
Then the interesting part in the URL is put inside a String type. To pass from URL type to String type some transformation are made. For example, replace all “<code>%20</code>” by space characters.
Then to show the String inside an HTML document, the string is put inside an HTML type. Some transformations occurs like replace “<code>&lt;</code>” by “<code>&amp;lt;</code>”.
Thanks to yesod, most of tedious string transformation job is done for us.</p>
<pre class="twilight">
<span class="String"><span class="String">&quot;</span>http://localhost:3000/echo/some%20text&lt;a&gt;<span class="String">&quot;</span></span>&nbsp;:: URL
<span class="String"><span class="String">&quot;</span>some text&lt;a&gt;<span class="String">&quot;</span></span> &nbsp;:: String
<span class="String"><span class="String">&quot;</span>some text &amp;lt;a&amp;gt;<span class="String">&quot;</span></span> &nbsp;:: HTML
</pre>
<p>That was the first very minimal example, and we already
verified Yesod protect us from many common errors.</p>
2011-12-30 16:14:57 +00:00
<h2 id="cleaning-up">Cleaning up</h2>
2011-12-29 16:05:05 +00:00
2011-12-30 16:14:57 +00:00
<p>This first example was nice, but for simplicity reason we didnt used best practices.</p>
2011-12-29 16:05:05 +00:00
2011-12-30 16:14:57 +00:00
<p>First we will separate the handler code into different files.
After that we will use <code>Data.Text</code> instead of <code>String</code>. </p>
2011-12-29 16:05:05 +00:00
2011-12-30 16:14:57 +00:00
<h3 id="separate-handlers">Separate handlers</h3>
2011-12-29 16:05:05 +00:00
2011-12-30 16:14:57 +00:00
<p>In a first time create a new file <code>Handler/Echo.hs</code> containing:</p>
<pre class="twilight">
<span class="Keyword">module</span> <span class="Constant">Handler</span>.<span class="Constant">Echo</span> <span class="Keyword">where</span>
<span class="Keyword">import</span> <span class="Constant">Import</span>
<span class="Entity">getEchoR</span>&nbsp;:: <span class="Constant">String</span> &rarr; <span class="Constant">Handler</span> <span class="Constant">RepHtml</span>
getEchoR theText = <span class="Keyword">do</span>
defaultLayout $ <span class="Keyword">do</span>
[whamlet|&lt;h1&gt;#{theText}|]
</pre>
<p>Do not forget to remove the getEchoR function inside the <code>Handler/Root.hs</code> file.</p>
<p>We must declare the file inside the cabal configuration file <code>yosog.cabal</code>. Just after <code>Handler.Root</code> add:</p>
<pre>
Handler.Echo
</pre>
<p>We must also declare the new Handler module inside <code>Application.hs</code>.
Just after the “<code>import Handler.Root</code>”, add:</p>
<pre class="twilight">
<span class="Keyword">import</span> <span class="Constant">Handler</span>.<span class="Constant">Echo</span>
</pre>
<h3 id="use-datatext-instead-of-string">Use <code>Data.Text</code> instead of <code>String</code></h3>
<p>Now our handler is separated in another file.</p>
<p>But we used <code>String</code> but it is a good practice to use <code>Data.Text</code> instead.</p>
<p>To declare we will use <code>Data.Text</code> we modify the file <code>Foundation.hs</code>.
Add an import directive just after the last one:</p>
<pre class="twilight">
import Data.Text
</pre>
<p>And also we must modify <code>config/routes</code> and our handler accordingly. Replace <code>#String</code> by <code>#Text</code> in <code>config/routes</code>:</p>
<pre>
/echo/#Text EchoR GET
</pre>
<p>And do the same in <code>Handler/Echo.hs</code>:</p>
<div class="code"><div class="file"><a href="/Scratch/en/blog/Yesod-tutorial-for-newbies/code/Echo.hs"> &#x27A5; Echo.hs </a></div><div class="withfile">
<pre class="twilight">
<span class="Keyword">module</span> <span class="Constant">Handler</span>.<span class="Constant">Echo</span> <span class="Keyword">where</span>
<span class="Keyword">import</span> <span class="Constant">Import</span>
<span class="Entity">getEchoR</span>&nbsp;:: <span class="Constant">Text</span> &rarr; <span class="Constant">Handler</span> <span class="Constant">RepHtml</span>
getEchoR theText = <span class="Keyword">do</span>
defaultLayout $ <span class="Keyword">do</span>
[whamlet|&lt;h1&gt;#{theText}|]
</pre>
</div></div>
<h3 id="use-a-new-template-file">Use a new template file</h3>
<p>The last thing to change in order to do things like in
a real project is to use another template file.</p>
<p>Just create a new file <code>template/echo.hamlet</code> containing:</p>
<div class="code"><div class="file"><a href="/Scratch/en/blog/Yesod-tutorial-for-newbies/code/echo.hamlet"> &#x27A5; echo.hamlet </a></div><div class="withfile">
<pre class="twilight">
&lt;h1&gt; #{theText}
</pre>
</div></div>
<p>and modify the handler <code>Handler/Echo.hs</code>:</p>
<pre class="twilight">
<span class="Entity">getEchoR</span>&nbsp;:: <span class="Constant">Text</span> &rarr; <span class="Constant">Handler</span> <span class="Constant">RepHtml</span>
getEchoR theText = <span class="Keyword">do</span>
defaultLayout $ <span class="Keyword">do</span>
$(widgetFile <span class="String"><span class="String">&quot;</span>echo<span class="String">&quot;</span></span>)
</pre>
2011-12-29 16:05:05 +00:00
<h2 id="protected-input">Protected input</h2>
<hr />
<div style="background-color: #800; color: #FFF; font-weight: bold; border: 2px solid #300; box-shadow: 0 0 60px #300 inset;padding-left: 2em;">
<h2 style="margin: 0 auto; text-align: center">TODO</h2>
<ul>
<li> Display something, show it is protected.
</li><li> Make the same as before, but with an input.
</li><li> Create a minimal blog system.
</li><li> Change template to html5 boilerplate.
</li><li> Use Authentification.
</li>
</ul>
</div>
</div>
<div id="choixrss">
<a id="rss" href="http://feeds.feedburner.com/yannespositocomen">
Subscribe
</a>
</div>
<script type="text/javascript">
$(document).ready(function(){
$('#comment').hide();
$('#clickcomment').click(showComments);
});
function showComments() {
$('#comment').show();
$('#clickcomment').fadeOut();
}
document.write('<div id="clickcomment">Comments</div>');
</script>
<div class="flush"></div>
<div class="corps" id="comment">
<h2 class="first">comments</h2>
<noscript>
You must enable javascript to comment.
</noscript>
<script type="text/javascript">
var idcomments_acct = 'a307f0044511ff1b5cfca573fc0a52e7';
var idcomments_post_id = '/Scratch/en/blog/Yesod-tutorial-for-newbies/';
var idcomments_post_url = 'http://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/';
</script>
<span id="IDCommentsPostTitle" style="display:none"></span>
<script type='text/javascript' src='/Scratch/js/genericCommentWrapperV2.js'></script>
</div>
<div id="entete" class="corps_spaced">
<div id="liens">
<ul><li><a href="/Scratch/en/">Home</a></li>
<li><a href="/Scratch/en/blog/">Blog</a></li>
<li><a href="/Scratch/en/softwares/">Softwares</a></li>
<li><a href="/Scratch/en/about/">About</a></li></ul>
</div>
<div class="flush"></div>
<hr/>
<div id="next_before_articles">
<div id="previous_articles">
previous entries
<div class="previous_article">
<a href="/Scratch/en/blog/SVG-and-m4-fractals/"><span class="nicer">«</span>&nbsp;Increase the power of deficient languages.</a>
</div>
<div class="previous_article">
<a href="/Scratch/en/blog/Yesod-excellent-ideas/"><span class="nicer">«</span>&nbsp;Yesod excellent ideas</a>
</div>
<div class="previous_article">
<a href="/Scratch/en/blog/programming-language-experience/"><span class="nicer">«</span>&nbsp;Programming Language Experience</a>
</div>
</div>
<div id="next_articles">
next entries
</div>
<div class="flush"></div>
</div>
</div>
<div id="bottom">
<div>
<a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/">Copyright ©, Yann Esposito</a>
</div>
<div id="lastmod">
Created: 12/28/2011
Modified: 12/29/2011
</div>
<div>
Entirely done with
<a href="http://www.vim.org">Vim</a>
and
<a href="http://nanoc.stoneship.org">nanoc</a>
</div>
<div>
<a href="/Scratch/en/validation/">Validation</a>
<a href="http://validator.w3.org/check?uri=referer"> [xhtml] </a>
.
<a href="http://jigsaw.w3.org/css-validator/check/referer?profile=css3"> [css] </a>
.
<a href="http://validator.w3.org/feed/check.cgi?url=http%3A//yannesposito.com/Scratch/en/blog/feed/feed.xml">[rss]</a>
</div>
</div>
<div class="clear"></div>
</div>
</body>
</html>