A simple, sinatra-inspired web framework.

Latest on Hackage:0.0.19

This package is not currently in any snapshots. If you're interested in using it, we recommend adding it to Stackage Nightly. Doing so will make builds more reliable, and allow to host generated Haddocks.

BSD-3-Clause licensed by Parker, Matt
Maintained by Parker, Matt


A sinatra-ish web framework written in haskell, riding on top of Hack.


Sinatra has a beautiful, simple, elegant syntax, but it’s essentially an attempt to bring pattern matching to a language never intended for pattern matching. Why not attempt something similar in a language with not just beautiful pattern matching, but with all the declarative bells and whistles: lazy evaluation, first-class functions, currying, polymorphism?


λ cabal update && cabal install bird

Note: make sure $HOME/.cabal/bin is in your PATH.

Create an app

λ bird hatch StarWars
  A fresh bird app has been created in StarWars.

Compile your app

λ cd StarWars
λ bird nest 
  [1 of 2] Compiling StarWars           ( StarWars.hs, StarWars.o )
  [2 of 2] Compiling Main               ( Main.hs, Main.o )
  Linking Main ...

Start your app (runs on port 3000)

λ bird fly
  A bird was just spotted in flight at http://localhost:3000

Try it out

λ curl http://localhost:3000
  Hello, Bird!


-- StarWars.bird.hs
import Data.String.Utils (join)

get ["droids"] = do
  body "These aren't the droids you're looking for. Move along."
  status 404

post ["jedi"] = do
  name <- param "name"
  teacher <- param "teacher"
  case teacher of 
    Just "Yoda" -> body "The force is strong with this one!"      >> status 201
    _           -> body "Sorry. The force is not with this one."  >> status 400 

get ("force":xs) = do
  body $ "May the force be with you " ++ (join ", " xs) ++ "!"

get [] = do
  name <- param "name"
  log "I'm about to greet a Jedi. Teehee!"
  body $ "Greetings, " ++ (maybe "Jedi!" id name)

Now recompile your app and start it flying:

λ bird nest
λ bird fly &

λ curl -i http://localhost:3000/force/Han/Chewie

    HTTP/1.1 200 OK
    Connection: close
    Content-Type: text/html
    Date: Sat, 31 Jul 2010 14:07:17 GMT
    Server: Happstack/

    May the force be with you Han, Chewie!

λ curl -i -X POST http://localhost:3000/jedi -d name=Luke -d teacher=Yoda
    HTTP/1.1 201 Created
    Connection: close
    Content-Type: text/html
    Date: Sat, 21 Aug 2010 21:38:11 GMT
    Server: Happstack/

    The force is strong with this one!

λ curl -i http://localhost:3000/droids

    HTTP/1.1 404 Not Found
    Connection: close
    Content-Type: text/html
    Date: Sat, 31 Jul 2010 14:08:35 GMT
    Server: Happstack/

    These aren't the droids you're looking for. Move along.


You have four functions to implement: get, post, put, and delete. They each accept a Bird Request.

Inside the function body, you can use the following methods (don’t worry, this is a growing list):

param :: String -> Maybe String
-- ex: for the request GET /droids?name=c3po,
--     then `p <- param "name"' would bind the value `Just "c3po"' to the variable "p"

body :: String -> BirdResponder ()
-- takes a string and sets the Http Response body to whatever the string contained.

status :: Integer -> BirdResponder ()
-- takes a number, and sets the HTTP Reponse header "Status" to that number.

mime :: String -> BirdResponder ()
-- sets the mime type to whatever you provide
-- ex: get [] = body "Hello World" >> mime "text/plain"

header :: String -> String -> BirdResponder ()
-- creates/updates a header
-- ex: get [] = body "Hello World" >> header "X-Powered-By" "BIRD!"

log :: String -> BirdResponder ()
-- adds to the log
-- ex: get [] = body "Hello World" >> log "Why did I just greet the world?"


This project is still in its infancy. Coming features:

  • support for multipart forms submissions
  • helpers for popular html generation solutions (Hamlet, HStringTemplate, HAXML, BlazeHTML, etc.)
  • WAI support
  • static asset serving
  • support for sending files
comments powered byDisqus