packages feed

hack-2009.4.25: readme.md

Hack: a sexy Haskell Webserver Interface
========================================


Hack is a brain-dead port of the brilliant Ruby [Rack](http://rack.rubyforge.org/) webserver interface.

What does a Hack app look like
------------------------------


    module Main where

    import Hack
    import Hack.Handler.Kibro

    hello :: Application
    hello = \env -> return $ Response 
        { status  = 200
        , headers = [ ("Content-Type", "text/plain") ]
        , body    = "Hello World"
        }

    main = run hello

1 minute tutorial
-----------------

### Install Hack

    cabal install hack

### Install Kibro (the only handler at the moment)

    cabal install kibro

### Install lighttpd 1.4.19 (used by kibro)

    wget http://www.lighttpd.net/download/lighttpd-1.4.19.tar.gz
    tar zxfv lighttpd-1.4.19.tar.gz
    cd lighttpd-1.4.19
    ./configure --prefix=$HOME
    make
    make install

### Create a new Kibro project

    kibro new hello-world

### Test if Kibro works

    cd hello-world
    kibro start

### Create a Hack app

put the following code in `src/Main.hs`

    module Main where

    import Hack
    import Hack.Handler.Kibro

    hello :: Application
    hello = \env -> return $ Response 
        { status  = 200
        , headers = [ ("Content-Type", "text/plain") ]
        , body    = "Hello World"
        }

    main = run hello


restart kibro

    kibro restart

Middleware
-----------

### demo usage of middleware

    module Main where

    import Hack
    import Hack.Utils
    import Hack.SimpleRoute
    import Hack.Handler.Kibro

    import Data.Default
    import MPS
    import Prelude hiding ((.))
    
    hello :: Application
    hello = \env -> def {body = env.show} .return

    app :: Application
    app = route [("/hello", hello), ("", hello)] empty_app

    main = run app

### create a middleware

inside Hack.hs:

    type MiddleWare = Application -> Application

since Haskell has curry, middleware api can be of type

    Anything -> Application -> Application

just pass an applied middleware into a chain.

finally the source code of SimpleRoute.hs:

    {-# LANGUAGE QuasiQuotes #-}

    module Hack.Contrib.SimpleRouter where

    import Hack
    import Hack.Utils
    import List (find)
    import Prelude hiding ((.), (^), (>))
    import MPS

    type RoutePath = (String, Application)

    route :: [RoutePath] -> MiddleWare
    route h _ = \env ->
      let path             = env.path_info
          script           = env.script_name
          mod_env location = env 
            { script_name  = script ++ location
            , path_info    = path.drop (location.length)
            }
      in
      case h.find (fst > flip starts_with path) of
        Nothing -> not_found [$here|Not Found: #{path}|]
        Just (location, app) -> app (mod_env location)

### Use the middleware stack

Rack provides a builder DSL, Hack just use a function. From `Utils.hs`:

    -- usage: app.use [content_type, cache]
    use :: [MiddleWare] -> MiddleWare
    use = reduce (<<<)

Handlers
--------


Just like Rack, once an application is written using Hack, it should work on any web server that provides a Hack handler. I'm only familiar with Kibro, so it became the first handler that's included.

The handler should expose only one function of type:

    run :: Application -> IO ()

Spec
----

Hack spec = Rack spec :) 

Please read [The Rack interface specification](http://rack.rubyforge.org/doc/files/SPEC.html).

Links
-----

* [Rack](http://rack.rubyforge.org/ )
* [Rack wiki](http://wiki.github.com/rack/rack)
* [Rack source](http://github.com/rack/rack/tree/master )
* [rack-contrib source](http://github.com/rack/rack-contrib/tree/master)