I wanted to try out some of Haskells web-frameworks for quite some time now. The problem so far was always the huge pile of things those come bundeled with (template haskell, conduit, comonads, etc.) and I somehow wanted to understand all this first.
To make this short: NO I do not understand all this but I think I will never really be ready to try it if I wait for me to turn genius overnight (guess will never happen) – so I just hold my breath and jump right into it!
but say … which one?
That leaves me with the choice of the framework. After looking a bit at the online tutorials I wanted to go for either snap or yesod.
But on first glance (well …) snap seemed to be a bit easier to get startet.
Having said that I think I will try yesod too someday soon.
Installation Odyssee
First try: Windows
I work mainly on Windows and so of course I tried to get this working in windows. I even can remember that I tried to install snap some time ago and it seemed to work … but …
Well after
cabal-dev install snap
I soon (well it took quite some time to compile all this) got the dreaded “failed to install because of …” message …
About an hour (with yet another complete reinstall of Haskell-Plattform and various test with different versions) later I finally contacted the snap guys on their IRC channel and after describing the problems the final verdict was like this:
we have no Windows developer on our team … this is about the help you can expect
To be honest: the guy was quite helpful and it seems that the problem is in some crypto-package and not with snap but I’m quite disappointed anyway.
Anyhow: forget Windows for now …
Ubuntu to the rescue….
Luckily I have quite a nice Ubuntu-VM installed on my machine (where I can just do a simple snapshot-restore to reset my cabal-hell) and so I went there next.
Here the installation was quite simple (that is
cabal-dev install snap
) worked just fine.
TIP OF THE DAY
I did not really want to do this installation for each project I am going to try but on Linux (have to try this on Windows as well) you can add a symbolic link to the created cabal-dev folder in each new project you are going to make (do not forget to place a symbolic link to the snap executable in cabal-dev/bin somewhere your PATH is pointing – or add this folder to your path.
This works quite nice for me and I do not soil my global or user cabal repository.
first toy project
For my first project I want to implement a basic calculator on a webpage.
Finally it should work with AJAX/jQuery or even do all it’s calculation in the browser using Fay.
First Iteration – getting something up
I worked through the two basic tutorials on the snap homepage: hello world and snaplets tutorial but two be honest – the second one just produced “WTF”s on my side – so I decided to keep it dumb for now and just get snap to serve me static HTML files together with a simple CSS stylesheet and of course a jQuery-plugin I am going to use (yeah … it’s JavaScript … for now).
You can find the project on github but so far it’s only a very basic extension of the first example above.
some details on the code
To get snap to serve me the stylesheets and possible scripts I had to extend the routes in the site-function:
site :: Snap () site = ifTop (serveDirectory "./content/") <|> route [ ("api/sum/:operants", sumHandler) ] <|> dir "scripts" (serveDirectory "./scripts/") <|> dir "styles" (serveDirectory "./styles/")This basically says that everything requested in with only the root-path is served (with some so called default-configuration) via serveDirectory straight from the content-folder (the default configuration sees that index.html is served … btw: Index.html will get you a 404)
The next part will serve for AJAX-requests – it binds a handler sumHandler to a URL like this http://mySite/api/sum/2%202 (see below).
The rest are static routes: /scripts/xyz tries to find the file xyz in the ./scripts folder and similar for styles (this is where I put the javascript files and the stylesheets).
The handler for the very simple API is implemented like this:
sumHandler :: Snap () sumHandler = do param <- getParam "operants" maybe (writeJSON errorMsg) (writeJSON . sumString . unpack) param where errorMsg :: ByteString errorMsg = pack "please give some operants" sumString :: String -> Integer sumString = sumUp . words where sumUp :: [String] -> Integer sumUp = sum . map readIt gets the string xyz in http://mySite/api/sum/xyz, splits it by spaces (words) and sums the integers (no there is no exception handling yet) up.
It finally serves the answer as JSON (for this I use the snap-extras package).I’m sure there is an easier way to do all this but this is what I was able to find in a reasonable time using my google-ninja-skills.
next Iteration: getting a basic web-page and AJAX queries to work …
well … but next time
to my dear reader:
I am sure some/most of you know better then me, so pls let me know what and how I can improve.
For example: is this the right way to get to some kind of RESTful API (using handlers like this) or is there some special snap-way I just have not found yet?