Building a REST application server in Haskell Part 1

November 07, 2010 - happstack haskell json rest

As mentioned previously, I’m boning up on Haskell. I prefer to learn by doing, so I’m attempting to build a functioning application as part of the process. I’ve struggled to find much entry level (real application) source code, so I'll be posting my progress as I go in the hope that it will help others undertaking the same journey. Note the emphasis is on ‘entry level’ — I'm not pretending to be a Haskell guru; if you are one, pointing out what I’m doing wrong would be much appreciated.

This application is a hypothetical REST-based continuous integration status aggregator — CI servers publish build results to the server, then mobile clients view the results. It seemed a little bit more interesting than another blog app tutorial. I’ll be using the popular happstack web application framework, serving JSON over its built-in web server.

First, the setup. Assuming you have a GHC distribution and cabal installed on your computer (on OS X, the Haskell platform binary installer includes these), you'll need to install happstack and JSON:

cabal update
cabal install happstack
cabal install json

If you get happstack build errors, see my previous post for a possible resolution.

First step is returning some JSON from the server. The following code is a minimal implementation that serialises some hard-coded test data and returns it in response to a web request:

{-# LANGUAGE DeriveDataTypeable #-}
module Main where

import Happstack.Server
import Text.JSON.Generic

data Project =
	Project {
		name :: String,
		lastStatus :: String,
		builds :: [Build]
	}
	deriving (Data, Typeable)

data Build =

	Build {
		buildName :: String,
		status :: String
 	}
	deriving (Data, Typeable)

testProjectJSON = encodeJSON (Project "New Project" "Succeeded" [Build "2010-10-02 build 2" "Succeeded", Build "2010-10-01 build 1" "Failed"])

main = simpleHTTP nullConf $ ok $ toResponse testProjectJSON

I'm using Text.JSON.Generic and the DeriveDataTypeable language extension to automatically generate mappings from my custom algebraic data types (Project & Build) to JSON. Using the standard Text.JSON library would require implementing showJSON and readJSON functions manually, eg something like:

instance JSON Project where
	showJSON (Project name lastStatus builds) = showJSON makeObj [("name", toJSString name), ("lastStatus", toJSString lastStatus), ("builds", showJSONs builds)]

My gut feel, although this is probably the OO developer in me talking, is that automatic generation would be better suited to simple serialisation problems, and explicit serialisation more useful in instances where C#/Java devs would think ‘DTO’ (eg producing a flattened, version-tolerant data contract).

Running the application should result in the following highly enlightening data being served from http://localhost:8000/

{"name":"New Project","lastStatus":"Succeeded","builds": [{"buildName":"2010-03-23","status":"Succeeded"},{"buildName":"2010-10-01","status":"Failed"}]}