View
243
Download
0
Category
Preview:
Citation preview
8/12/2019 Haskell Web Programming
1/15
Haskell web programming
A Yesod tutorial
update: updated for yesod 0.10
tl;dr: A simple yesod tutorial. Yesod is a Haskell web framework. You shouldnt need toknow Haskell.
Table of content
Before the real start
o Install
o Initialie
o !onfi"ure "it
o #ome last minute words
$%ho
o Bulletproof&
o !leanin" up
'se a better %ss
#eparate Handlers Data.Text
'se templates
(irror
A Blo"
!on%lusion
)hy Haskell&
1
http://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/#before-the-real-starthttp://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/#installhttp://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/#initializehttp://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/#configure-githttp://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/#some-last-minute-wordshttp://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/#echohttp://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/#bulletproofhttp://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/#cleaning-uphttp://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/#use-a-better-span-classsccssspanhttp://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/#separate-handlershttp://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/#datatexthttp://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/#datatexthttp://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/#use-templateshttp://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/#mirrorhttp://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/#a-bloghttp://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/#conclusionhttp://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/#before-the-real-starthttp://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/#installhttp://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/#initializehttp://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/#configure-githttp://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/#some-last-minute-wordshttp://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/#echohttp://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/#bulletproofhttp://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/#cleaning-uphttp://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/#use-a-better-span-classsccssspanhttp://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/#separate-handlershttp://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/#datatexthttp://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/#use-templateshttp://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/#mirrorhttp://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/#a-bloghttp://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/#conclusion8/12/2019 Haskell Web Programming
2/15
Its effi%ien%y *see #nap Ben%hmark&)arp Ben%hmark1+. Haskell is an order of ma"nitude
faster than interpreted lan"ua"es like ,ubyand-ython.
http://snapframework.com/blog/2010/11/17/snap-0.3-benchmarkshttp://www.yesodweb.com/blog/2011/03/preliminary-warp-cross-language-benchmarkshttp://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/#fn:benchmarkdigressionhttp://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/#fn:benchmarkdigressionhttp://shootout.alioth.debian.org/u64q/benchmark.php?test=all&lang=ghc&lang2=yarvhttp://shootout.alioth.debian.org/u64q/benchmark.php?test=all&lang=ghc&lang2=yarvhttp://shootout.alioth.debian.org/u64q/benchmark.php?test=all&lang=ghc&lang2=python3http://shootout.alioth.debian.org/u64q/benchmark.php?test=all&lang=ghc&lang2=python3http://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/#fn:speeddigressionhttp://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/#fn:speeddigressionhttp://snapframework.com/blog/2010/11/17/snap-0.3-benchmarkshttp://www.yesodweb.com/blog/2011/03/preliminary-warp-cross-language-benchmarkshttp://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/#fn:benchmarkdigressionhttp://shootout.alioth.debian.org/u64q/benchmark.php?test=all&lang=ghc&lang2=yarvhttp://shootout.alioth.debian.org/u64q/benchmark.php?test=all&lang=ghc&lang2=python3http://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/#fn:speeddigression8/12/2019 Haskell Web Programming
3/15
Haskell is a hi"h le/el lan"ua"e and make it harder to shoot you in the foot than C C++or
Javafor eample. 2ne of the best property of Haskell bein":
3If your pro"ram %ompile it will be /ery %lose to what the pro"rammer intended4.
Haskell web frameworks handle parallel tasks perfe%tly. 5or eample e/en better thannode.6s7.
5rom the pure te%hni%al point of /iew Haskell seems to be the perfe%t web de/elopment tool.)eaknesses of Haskell %ertainly wont be te%hni%al:
Hard to "rasp Haskell
Hard to find a Haskell pro"rammer
8he Haskell %ommunity is smaller than the %ommunity for /.*/
8here is no herokufor Haskell *e/en if 9re" )eber did it it was more a workaround+.
I wont say these are not important drawba%ks. But with Haskell your web appli%ation will
ha/e both properties to absorb an impressi/e number of parallel reuest se%urely and to adapt
to %han"e.
A%tually there are three main Haskell web frameworks:
1. Happsta%k
. #nap
7. Yesod
I dont think there is a real winner between these three framework. 8he %hoi%e I made for
yesod is hi"hly sub6e%ti/e. I 6ust lurked a bit and tried some tutorials. I had the feelin" yesod
make a better 6ob at helpin" new%omers. 5urthermore apparently the yesod team seems the
most a%ti/e. 2f %ourse I mi"ht be wron" sin%e it is a matter of feelin".
7
http://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/#fn:nodejstrollhttp://heroku.com/http://www.yesodweb.com/blog/2011/07/haskell-on-herokuhttp://happstack.com/http://snapframework.com/http://yesodweb.com/http://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/#fn:nodejstrollhttp://heroku.com/http://www.yesodweb.com/blog/2011/07/haskell-on-herokuhttp://happstack.com/http://snapframework.com/http://yesodweb.com/8/12/2019 Haskell Web Programming
4/15
)hy did I write this arti%le& 8he yesod do%umentation and parti%ularly the book are
e%ellent. But I missed an intermediate tutorial. 8his tutorial wont eplain all details. I tried
to "i/e a step by step of how to start from a fi/e minute tutorial to an almost produ%tion ready
ar%hite%ture. 5urthermore eplainin" somethin" to others is a "reat way to learn. If you are
used to Haskell and Yesod this tutorial wont learn you mu%h. If you are %ompletely new to
Haskell and Yesod it mi"ht hopefully helps you. Also if you find yourself too %onfused by
the synta it mi"ht helps to read this arti%le
urin" this tutorial youll install initialie and %onfi"ure your first yesod pro6e%t. 8hen there
is a /ery minimal < minutes yesod tutorial to heat up and /erify the awesomeness of yesod.8hen we will %lean up the < minutes tutorial to use some 3best pra%ti%es4. 5inally there will
be a more standard real world eample; a minimal blo" system.
Before the real start
Install
8he re%ommended way to install Haskellis to download the Haskell -latform.
2n%e done you need to install yesod. 2pen a terminal session and do:
~ cabal update~ cabal install yesod cabal-dev
8here are few steps but it should take some time to finish.
Initialize
You are now ready to initialie your first yesod pro6e%t. 2pen a terminal and type:
~ yesod init
=
http://blog.ezyang.com/2011/11/how-to-read-haskell/http://www.haskell.org/http://www.haskell.org/platformhttp://blog.ezyang.com/2011/11/how-to-read-haskell/http://www.haskell.org/http://www.haskell.org/platform8/12/2019 Haskell Web Programming
5/15
$nter your name %hoose yosogfor the pro6e%t name and enter Yosogfor the name of the
5oundation. 5inally %hoose sqlite. >ow start the de/elopment %y%le:
~ cd yosog~ cabal-dev install && yesod --dev devel
8his will %ompile the entire pro6e%t. Be patient it %ould take a while the first time. 2n%e
finished a ser/er is laun%hed and you %ould /isit it by %li%kin" this link:
ttp!//localost!"###
!on"ratulation? Yesod works?
>ote: if somethin" is messed up use the followin" %ommand line inside the pro6e%t dire%tory.$% -%' dist/* ( cabal-dev install && yesod --dev devel
'ntil the end of the tutorial use another terminal and let this one open in a %orner to see whato%%urs.
Configure git
2f %ourse this step is not mandatory for the tutorial but it is a "ood pra%ti%e.
!opy this .gitigno%efile into the yosogfolder.
."iti"norecabal-dev
dist.static-cacestatic/tp*.sqlite"
8hen initialie your "it repository:
~ git init .~ git add .~ git coit -a - )nitial yesod coit)
)e are almost ready to start.
Some last minute words
'p until here we ha/e a dire%tory %ontainin" a bun%h of files and a lo%al web ser/er listenin"
the port 7000. If we modify a file inside this dire%tory yesod should try to re%ompile as fast
as possible the site. Instead of eplainin" the role of e/ery file lets fo%us only on the
important files@dire%tories for this tutorial:
1. con'ig/%outes
. andle%/
7. teplates/
=. con'ig/odels
8/12/2019 Haskell Web Programming
6/15
2b/iously:
con'ig/%outes is where youll %onfi"ure the map url !ode.
andle%/ %ontains the files that will %ontain the %ode %alled when a url is a%%essed.
teplates/ %ontains html 6s and %ss templates.
con'ig/odels is where youll %onfi"ure the persistent ob6e%ts *database tables+.
urin" this tutorial well modify other files as well but we wont eplore them in detail.
Also note shell %ommands are ee%uted in the root dire%tory of your pro6e%t instead spe%ified
otherwise.
)e are now ready to start?
Echo
8o /erify the uality of the se%urity of the yesod framework lets make a minimal e%ho
appli%ation.
9oal:
(ake a ser/er that when a%%essed /eco/,soe textshould return a web pa"e %ontainin"
3some tet4 inside an blo%.
In a first time we must de%lare the url of the form /eco/...are meanin"ful. ets take a
look at the file con'ig/%outes:
/static tatic0 tatic gettatic/aut 1ut0 1ut get1ut
/'avicon.ico 2avicon0 34T/%obots.txt 0obots0 34T
/ oe0 34T
)e want to add a route of the form /eco/,anytingsomehow and do some a%tion with
this. Add the followin":
/eco/5t%ing 4co0 34T
8his line %ontains three elements: the url pattern a handler name an http method. I am not
parti%ularly fan of the bi" , notation but this is the standard %on/ention.
If you sa/e con'ig/%outes you should see your terminal in whi%h you laun%hed yesod
devela%ti/ate and %ertainly displayin" an error messa"e.
1pplication.s!"!! 6ot in scope! 7get4co08
)hy& #imply be%ause we didnt written the %ode for the handler 4co0. $dit the fileandle%/oe.sand append this:
C
8/12/2019 Haskell Web Programming
7/15
get4co0 !! t%ing -9 andle% 0eptlget4co0 teText : do de'ault;ayout < do ,=alet>?95@teTextA>
ont worry if you find all of this a bit %rypti%. In short it 6ust de%lare a fun%tion named
get4co0with one ar"ument *teText+ of type #trin". )hen this fun%tion is %alled it returna andle% 0eptlwhate/er it is. But mainly this will en%apsulate our epe%ted result
inside an html tet.
After sa/in" the file you should see yesod re%ompile the appli%ation. )hen the %ompilation
is finished youll see the messa"e: ta%ting devel application.
>ow you %an /isit: ttp!//localost!"###/eco/YesodB#%ocsE
8AA? It works?
Bulletproof
$/en this etremely minimal web appli%ation has some impressi/e properties. 5or eemple
ima"ine an atta%ker enterin" this url:
ttp!//localost!"###/eco/?a98 ?sc%ipt9ale%tF)GadE)H(
8he spe%ial %hara%ters are prote%ted for us. A mali%ious user %ould not hide some bad s%ript
inside.
8his beha/ior is a dire%t %onseuen%e of type safety. 8he url strin" is put inside a url type.
8hen the interestin" part in the url is put inside a #trin" type. 8o pass from url type to #trin"
type some transformation are made. 5or eample repla%e all 3B#4 by spa%e %hara%ters. 8hen
to show the #trin" inside an html do%ument the strin" is put inside an html type. #ome
transformations o%%urs like repla%e 3?4 by 3<(4. 8hanks to yesod this tedious 6ob is donefor us.
D
http://localhost:3000/echo/Yesod%20rocks!http://localhost:3000/echo/%3Ca%3EI'm%20%3Cscript%3Ealert(%22Bad!%22);http://localhost:3000/echo/Yesod%20rocks!http://localhost:3000/echo/%3Ca%3EI'm%20%3Cscript%3Ealert(%22Bad!%22);8/12/2019 Haskell Web Programming
8/15
)ttp!//localost!"###/eco/soeB#text?a9) !! I0; )soe text?a9) !! t%ing )soe text ?a9) !! tl
Yesod is not only fast it helps us to remain se%ure. It prote%ts us from many %ommon errorsin other paradi"ms. Yes I am lookin" at you -H-?
Cleaning up
$/en this /ery minimal eample should be enhan%ed. )e will %lean up many details:
'se a "eneral %ss *%leaner than the empty by default+
ispat%h handler %ode into different files
'se Data.Textinstead of t%ing
-ut our 3/iews4
=
inside the teplatedire%tory
!se a better css
It is ni%e to note the default template is based on html< boilerplate. ets %han"e the default
%ss. Add a file named de'ault-layout.luciusinside the teplates/dire%tory %ontainin":
defaultElayout.lu%iusbody @ 'ont-'aily! elveticaK sans-se%i'(
'ont-siLe! Mpx( A5ain @
padding! e( bo%de%! 5CCC solid px( bo%de%-%adius! Npx( a%gin! e( =idt! "Oe( a%gin! e auto( bacg%ound! 5222( line-eigt! .Ne( colo%! 5"""( A.%equi%ed @ a%gin! e #( A.optional @ a%gin! e #( Alabel @ =idt! Me( display! inline-bloc( AinputK texta%ea @ bacg%ound! 5212121A
texta%ea @ =idt! Oe( eigt! Pe(Aul @ list-style! squa%e( Aa @ colo%! 51NQ( Aa!ove% @ colo%! 5CNM( Aa!active @ colo%! 5CNM( Aa!visited @ colo%! 5PR"( A
-ersonally I would prefer if su%h a minimal %ss was put with the s%affoldin" tool. I am sure
somebody already made su%h a minimal %ss whi%h "i/e the impression the browser handle
%orre%tly html without any style applied to it. But I di"ress.
Separate Handlers
F
http://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/#fn:explainviewwidgethttp://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/#fn:explainviewwidgethttp://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/code/default-layout.luciushttp://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/code/default-layout.luciushttp://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/code/default-layout.luciushttp://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/#fn:explainviewwidgethttp://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/code/default-layout.lucius8/12/2019 Haskell Web Programming
9/15
9enerally you dont want to ha/e all your %ode inside a uniue file. 8his is why we will
separate our handlers. In a first time %reate a new file andle%/4co.s%ontainin":
odule andle%.4co =e%e
ipo%t po%t
get4co0 !! t%ing -9 andle% 0eptlget4co0 teText : do de'ault;ayout < do ,=alet>?95@teTextA>
o not for"et to remo/e the "et$%ho, fun%tion inside andle%/oe.s.
)e must de%lare this new file intoyosog.cabal. Gust after andle%.oe add:
andle%.4co
)e must also de%lare this new Handler module inside 1pplication.s. Gust after the
3ipo%t andle%.oe4 add:
ipo%t andle%.4co
8his is it.
ps:I am sure not so far in the future we %ould simply write yesod add-andle% 4coto de%lare it and
%reate a new handler file.
Data.Text
It is a "ood pra%ti%e to use Data.Textinstead of t%ing.
8o de%lare it add this import dire%ti/e to 2oundation.s*6ust after the last one+:
ipo%t Data.Text
)e ha/e to modify con'ig/%outesand our handler a%%ordin"ly. ,epla%e 5t%ingby 5Text
in con'ig/%outes:
/eco/5Text 4co0 34T
And do the same in andle%/4co.s:
$%ho.hsodule andle%.4co =e%e
ipo%t po%t
get4co0 !! Text -9 andle% 0eptlget4co0 teText : do de'ault;ayout < do ,=alet>?95@teTextA>
!se templates
http://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/code/Echo.hshttp://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/code/Echo.hshttp://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/code/Echo.hshttp://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/code/Echo.hs8/12/2019 Haskell Web Programming
10/15
#ome html *more pre%isely hamlet+ is written dire%tly inside our handler. )e should put this
part inside another file. !reate the new file teplates/eco.alet %ontainin":
e%ho.hamlet?9 5@teTextA
and modify the handler andle%/4co.s:
get4co0 !! Text -9 andle% 0eptlget4co0 teText : do de'ault;ayout < do
8/12/2019 Haskell Web Programming
11/15
getSi%%o%0 !! andle% 0eptlgetSi%%o%0 : do de'ault;ayout < do
8/12/2019 Haskell Web Programming
12/15
5irst we de%lare another model ob6e%t. Append the followin" %ontent to con'ig/odels:
1%ticle title Text content tl
de%iving
As tlis not an instan%e of 0ead o=and 4q we had to add the de%ivingline. If you
for"et it there will be an error.
After the route and the model we write the handler. 5irst de%lare a new Handler module.
Add ipo%t andle%.Gloginside 1pplication.sand add it into yosog.cabal. ets
write the %ontent of andle%/Glog.s. )e start by de%larin" the module and by importin"
some blo%k ne%essary to handle Html in forms.
odule andle%.Glog F getGlog0
K postGlog0 K get1%ticle0 H=e%e
ipo%t po%t
-- to use tl into 'o%sipo%t Yesod.2o%.6ic FYesod6icK nictl2ieldHinstance Yesod6ic 1pp
,emark: it is a best pra%ti%e to add the Yesod>i% instan%e inside 2oundation.s. I put this definition here to
make thin"s easier but you should see a warnin" about this orphan instan%e. 8o put the in%lude inside
5oundation.hs is left as an eer%i%e to the reader.
Hint: Do not forget to put YesodNicand nicHtmlFieldinside the exported objects of the module.
ent%y2o% !! 2o% 1%ticleent%y2o% : %ende%Divs < 1%ticle ?
8/12/2019 Haskell Web Programming
13/15
arti%les.hamlet?9 1%ticles
8/12/2019 Haskell Web Programming
14/15
get1%ticle0 !! 1%ticled -9 andle% 0eptlget1%ticle0 a%ticled : do a%ticle ?- %unDG < getR#R a%ticled de'ault;ayout < do setTitle < totl < a%ticleTitle a%ticle
8/12/2019 Haskell Web Programming
15/15
ps:You %an download the sour%e of this yesod blo" tutorial at "ithub.%om@yo"sototh@yoso".
1. 2ne %an ar"ue these ben%hmark %ontains many problems. But the ben%hmarks are 6ust
here to "i/e an order of idea. (ainly Haskell is /ery fast.
. 9enerally high levelHaskell is slower than ! but low levelHaskell is eui/alent to !speed. It means that e/en if you %an easily link ! %ode with Haskell this is not needed
to rea%h the same speed. 5urthermore writin" a web ser/i%e in !@! seems to be a
/ery bad idea. You %an take a look at adis%ussion on H> about this.
7. If you are %urious you %an sear%h about the 5ibona%%i node.6s troll.)ithout any
tweakin" Haskell handled this problem perfe%tly. I tested it myself usin" yesod
instead of #nap.
=. By /iew I mean yesod wid"ets hamlet lu%ius and 6ulius files.
1
Recommended