Our first happstack application is a simple server that responds to all requests with the string, Hello, World!.
> module Main where > > import Happstack.Server (nullConf, simpleHTTP, toResponse, ok) > > main :: IO () > main = simpleHTTP nullConf $ ok "Hello, World!"
[Source code for the app is here.]
To build the application run:
The executable will be named helloworld.
Alternatively, you can use runhaskell and avoid the compilation step.
Run this app and point your browser at http://localhost:8000/. (assuming you are building the program on your local machine.)
If we point curl at the app we get the following output:
$ curl http://localhost:8000/ Hello, World!
The top-level function simpleHTTP
is what actually starts the program listening for incoming HTTP requests.
> simpleHTTP :: (ToMessage a) => Conf -> ServerPartT IO a -> IO ()
The first argument is some simple server configuration information. It is defined as:
> data Conf = Conf { port :: Int > , validator :: Maybe (Response -> IO Response) > , logAccess :: forall t. FormatTime t => > Maybe (String -> String -> t -> String -> Int -> > Integer -> String -> String -> IO ()) > , timeout :: Int > }
port
validator
logAccess
timeout
The default config is nullConf
which is simply defined as:
> -- | Default configuration contains no validator and the port is set to 8000 > nullConf :: Conf > nullConf = Conf { port = 8000 > , validator = Nothing > , logAccess = Just logMAccess > }
Request
The second argument is a bit more interesting. The ServerPartT IO a
is the code that actually processes an incoming HTTP Request
and generates a Response
. The ServerPartT IO
monad is essentially a fancy way of writing a function with the type:
> Request -> IO Response
simpleHTTP
processes each incoming request in its own thread. It will parse the Request
, call your ServerPartT
handler, and then return the Response
to the client. When developing your server part, it is natural to think about things as if you are writing a program which processes a single Request
, generates a Response
, and exits. However it is important when doing I/O, such as writing files to disk, or talking to a database to remember that there may be other threads running simultaneously.
In this example, our server part is simply:
> ok "Hello, World!"
ok
is one of several combinators which can be used to set the HTTP response code. In this case, it will set the response code to 200 OK
. Happstack.Server.SimpleHTTP
contains similar functions for the common HTTP response codes including, notFound
, seeOther
, badRequest
and more. These functions all act like the normal return
function, except they also set the response code.
Response
The body of the response will be "Hello, World!".
The String
"Hello, World!" is turned into a Response
because simpleHTTP calls toResponse
from the ToMessage
class on it. Often times we will opt to make this call explicit rather than implicit. For example:
> main :: IO () > main = simpleHTTP nullConf $ ok (toResponse "Hello, World!")
The toResponse
function takes care of setting the Content-type
and converting the value into a lazy ByteString
which will be sent back to the client. Happstack comes with pre-defined ToMessage
instances for many types such as Text.Html.Html
, Text.XHtml.Html
, String
, the types from HSP, and more.