This model-view-controller pattern has been kicking around for quite some time now. It’s a nice way of separating concerns in many applications including web apps. And, a modern web-framework should both let you separate concerns and, ideally, bridge the gap between your programming model and data storage model. Some really nice people have done this in Ruby and Python and Python and …. well you get the picture. If you like a programming language there are probably several modern web-frameworks for it. So can we ask that question about Haskell? How would a modern web-framework work in a language that allows easy parallelisation, straightforward concurrency and even software transactional memory. Here’s my brief take on three Haskell web frameworks, with the caveat that I’ve only used one in anger (unsurprisingly my favourite one).
Snap Framework has been getting a lot of press lately. It’s fast. Faster than node.js but if you look at the documentation it appears that it uses a similar model to node.js i.e. a fast event loop. Snap provides a templating language called Heist. It has a nice method of handling RESTful queries (code stolen from here)
site :: Application ()
site = route [ ("/", index)
, ("/echo/:stuff", echo)
]
serveDirectory "resources/static"
Which just fires things off to specific handlers. Nice. And, just for good measure, I’ve stolen this heist snippet too
<html>
<head>
<title>Home Page</title>
</head>
<body>
<h1>Home Page</h1>
<apply template="nav"/>
<p>Welcome to our home page</p>
</body>
</html>
Snap leaves the choice of a storage backend up to the developer. They’ve got good reasons for this, however if doesn’t endear me. I’m happer with smart people doing all the integration work and giving me something to use.
Yesod gives you the choice of using either sqlite or postgres as a backing store. And it’ll do automagic migration of database schemas. Defining a datatype for storage is simple
mkPersist [$persist|
Entry
title String
day Day Desc
content Html'
deriving
|]
Again, this code is stolen from the very excellent tutorial. But this is looking straightforward, I get a Haskell datatype that’s persisted to a standard, trustworthy relational data store. Now, the people who are writing Snap seem to be scary smart and like to make fast things even faster, but this guy who develops Yesod seems to want to give me all the tools I need to just make a web app. It’s worth looking at his screencasts to see how easy OpenID and Facebook authentication is in a Yesod app. Furthermore, Yesod provides Hamlet, Cassius and Julius – respectively HTML, CSS and JavaScript templating languages. Julius, in particular, seems to have been designed with jQuery in mind. This, again, makes sense to me. Someone is giving me great tools to produce web apps under the standard use-case i.e. nice RESTful blingy things. You can even see that the Yesod query routing is simple
mkYesod "Blog" [$parseRoutes|
/ RootR GET
/entry/#EntryId EntryR GET
/admin AdminR EntryCrud defaultCrud
|]
And finally we get to Happstack. Happstack is the most mature of the three and features a wonderful data store called MACID. MACID has acid super powers but it distributes. I get to store any Haskell structure I want in a secure, distributed data-store! Representing reasonably complex information is easy
$(deriveAll [''Show, ''Eq, ''Ord, ''Default]
[d|
-- |ConferenceSubmission: a paper submitted to the conference
data ConferenceSubmission = ConferenceSubmission
{ author :: String
, title :: String
, date :: ClockTime
, email :: String
}
-- |Conference: a list of ConferenceSubmission
newtype Conference = Conference { conferenceSubmissions :: [ConferenceSubmission] }
|])
Routing is a little hairy, but you get a lot of power from it. And it’s nicely monadic.
appHandler =
do decodeBody (defaultBodyPolicy "/tmp/" 4096 4096 4096) -- decode the request body if present.
msum [ methodM GET >> renderIndex -- matches /
, renderSubmissions =<< conferenceHandler
]
conferenceHandler :: ServerPartT IO (HSP XML)
conferenceHandler =
dir "submissions" $ msum [postSubmission, getEntries] -- RESTful /submissions
Happstack uses Blaze or HSP or many other options for its templating language. Again, Blaze and HSP both play well with jQuery.
I have a fun project to play with over the next few months. I think Happstack is what I’ll be using.