1. new in this version
  2. build a web 2.0 app in happstack
  3. why happstack is cool
  4. getting started with happstack
  5. prerequisites
  6. cabal install me
  7. first shot at happstack
  8. url handling
  9. basic HTML inclusion
  10. templates
  11. stringtemplate basics
  12. debugging
  13. form data: get and post
  14. form data: file uploads
  15. cookies
  16. introduction to macid
  17. first steps with macid
  18. scaling with multimaster
  19. using macid safely
  20. macid dummy data
  21. changing the data model
  22. macid stress test
  23. limitations of macid
  24. foreign characters
  25. IxSets
  26. cron jobs
  27. thanks
  28. appendix (floundering in ghci)

A first application with Happstack

Before we dive straight into the code that actually runs this tutorial, I want to take some time to walk you through the very basics of writing & running a Happstack application.

So first, fire up that trusty GHCi and import Happstack.Server. Then follow along with the steps below.

ghci>:i simpleHTTP
simpleHTTP :: (ToMessage a) => Conf -> ServerPartT IO a -> IO ()
-- Defined in Happstack.Server.SimpleHTTP
ghci>:i Conf
data Conf
= Conf {port :: Int, validator :: Maybe (Response -> IO Response)}
-- Defined in Happstack.Server.HTTP.Types
ghci> simpleHTTP (Conf 8080 Nothing) (return "Hello World!")

Now if you check your localhost:8080 you should see the text "Hello World!". Congratuations, you've now succesfully written & run a Happstack application. Now we'll take a little bit of time and explain what just happened.

First, look again at the type of simpleHTTP. Conceptually, we can already take a stab at what this means. simpleHTTP is a function that will take in a Conf and handler and then run the Happstack webserver. A Conf is, as can be seen, a fairly simple data type. It consists of the port number to listen on and a default validator to use for the application. We'll come back to using validators in a future chapter, but for now let's just say that they can be a convenient debugging tool and probably not something you want to use in a live application.

Now let's take a look at what makes up a ServerPartT:
ghci>:i ServerPartT
newtype ServerPartT m a
= ServerPartT {unServerPartT :: ReaderT Request (WebT m) a}
-- Defined in Happstack.Server.SimpleHTTP
instance [overlap ok] (Monad m) => Monad (ServerPartT m)
-- Defined in Happstack.Server.SimpleHTTP
instance [overlap ok] (Monad m) => Functor (ServerPartT m)
-- Defined in Happstack.Server.SimpleHTTP
instance [overlap ok] (Monad m) => MonadPlus (ServerPartT m)
-- Defined in Happstack.Server.SimpleHTTP
instance [overlap ok] MonadTrans ServerPartT
-- Defined in Happstack.Server.SimpleHTTP
instance [overlap ok] (MonadIO m) => MonadIO (ServerPartT m)
-- Defined in Happstack.Server.SimpleHTTP
instance [overlap ok] (Monad m, MonadReader r m) => MonadReader r (ServerPartT m)
-- Defined in Happstack.Server.SimpleHTTP
instance [overlap ok] (Monad m, MonadError e m) => MonadError e (ServerPartT m)
-- Defined in Happstack.Server.SimpleHTTP
instance [overlap ok] (Monad m) => Monoid (ServerPartT m a)
-- Defined in Happstack.Server.SimpleHTTP
instance [overlap ok] (Monad m) => ServerMonad (ServerPartT m)
-- Defined in Happstack.Server.SimpleHTTP
instance [overlap ok] (Monad m) => WebMonad Response (ServerPartT m)
-- Defined in Happstack.Server.SimpleHTTP
instance [overlap ok] (Monad m) => FilterMonad Response (ServerPartT m)
-- Defined in Happstack.Server.SimpleHTTP
instance [overlap ok] (Monad m, Functor m) => Applicative (ServerPartT m)
-- Defined in Happstack.Server.SimpleHTTP

My Goodness! That's a lot of instances! Some important ones we'll be using are the Monoid, Functor, MonadIO, and MonadTrans instances. The others will transparently enable much of the machinery of Happstack but don't require us to actively think about them.

I want to make one final note about simpleHTTP: did you notice the type restriction (ToMessage a) on the return type of the ServerPartT? Let's again whip out ghci and take a look at this class.

ghci>:i ToMessage
class ToMessage a where
toContentType :: a -> Data.ByteString.Internal.ByteString
toMessage :: a -> Data.ByteString.Lazy.Internal.ByteString
toResponse :: a -> Response

You many not need to call these methods explicitly for your own applications, but the ToMessage instance for the return type of your ServerPartT is going to determine how your handler's response will be displayed.

The minimal complete definition of ToMessage is toMessage. The default content type will be "text/plain".

Now, we'll move on to a slightly more complicated example and the slightly uglier cousin of simpleHTTP: simpleHTTP'

ghci>:i simpleHTTP'
(Monad m, ToMessage b) => (m (Maybe (Either Response a, FilterFun Response)) -> IO (Maybe (Either Response b, FilterFun Response)))
-> Conf
-> ServerPartT m a
-> IO ()

Please don't be alarmed by that type signature. This function is actually very simple for any cases you're likely to use. simpleHTTP itself is equivalent to simpleHTTP' id.

Take a look at the source of StateTExample.hs and then try running StateTExample with, for example, runghc StateTExample.hs.

If you navigate to localhost:8880 then you should see the little lonely number 1. Try it a few more times! Has the number changed at all? This is because each handling of a request will apply the (flip evalStateT 0) function, hence the state is restarted every time.

This example isn't the most useful because of its simplicity, but for complicated computations in the request handling the ability to have an inner monad other than IO can be convenient.

Next we'll be talking about a number of the conveniant combinators in an extended example.