Haskell Web Programming

Embed Size (px)

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/#conclusion
  • 8/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:speeddigression
  • 8/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/platform
  • 8/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&lt(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.lucius
  • 8/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.hs
  • 8/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