RESTful Web Services with Haskell


Andrew Farmer
http://andrewfarmer.name

Functional Programming Group
Information and Telecommunication Technology Center
University of Kansas

Lambda Lounge KC
November 20, 2013

HERMIT

image from http://www.angelfire.com/ks/larrycarter/LC/OldGuardCameron.html

HERMIT Demo

HERMIT Demo

HERMIT User Interface

Dr Scheme Arrows
Image from: http://people.cs.uchicago.edu/~jacobm/qstr/screenshot.gif

HERMIT User Interface

Dr Scheme Arrows

Great! We'll make a web application!

Image from: http://people.cs.uchicago.edu/~jacobm/qstr/screenshot.gif

Haskell Web Frameworks

Yesod Book
Obviously...
Images from: http://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/
and: http://shop.oreilly.com/product/0636920023142/ViewLarger.do?sortby=publicationDate

Request/Response Cycle

Request/Response Ladder Diagram

HERMIT HTTP API

POST /connect
  200 Token -- server is ready, gives back unique id 
            -- (to be sent with all subsequent requests)
  
POST /command Command
  200 CommandResponse -- glyphs and resulting AST
  200 Msg             -- some other response message

GET /commands
  200 CommandList

POST /history Token -- AST is ignored
  200 History

POST /complete Complete
  200 Completions

Responses which can be returned by ANY request:

400 Msg -- Bad Request (request was malformed)
500 Msg -- Internal Server Error (some other server error occurred)

Scotty

A declarative DSL for RESTful web applications.

Scotty's design taken from that of the Ruby language's Sinatra.

Demo1

{-# LANGUAGE OverloadedStrings #-}

import Web.Scotty

main = scotty 3000 (get "/" (html "<h1>Hello World</h1>"))

Demo2

{-# LANGUAGE OverloadedStrings #-}

import Data.Monoid

import Web.Scotty

main = scotty 3000 $ do
    get "/" $ do
        html "<h1>Hello World</h1>"

    get "/:word" $ do
        w <- param "word"
        html $ "<h1>Hello " <> w <> "</h1>"

Demo3

{-# LANGUAGE OverloadedStrings #-}

import Data.Monoid
import Data.String

import Web.Scotty

main = scotty 3000 $ do
    get "/" $ do
        html "<h1>Hello World</h1>"

    get "/:x" $ do
        x <- param "x"
        html $ "<h1>" <> fromString (show x) <> " + 54 = "
                      <> fromString (show (x+(54::Int))) <> "</h1>"

    get "/:word" $ do
        w <- param "word"
        html $ "<h1>Hello " <> w <> "</h1>"

Demo 4

{-# LANGUAGE OverloadedStrings #-}

import Data.Monoid
import Data.String

import Network.Wai.Middleware.RequestLogger

import Web.Scotty

main = scotty 3000 $ do
    middleware logStdoutDev

    get "/" $ do
        html "<h1>Hello World</h1>"

    get "/:x" $ do
        x <- param "x"
        html $ "<h1>" <> fromString (show x) <> " + 54 = "
                      <> fromString (show (x+(54::Int))) <> "</h1>"

    get "/:word" $ do
        w <- param "word"
        html $ "<h1>Hello " <> w <> "</h1>"

Demo 5

{-# LANGUAGE OverloadedStrings #-}

import Control.Applicative

import Data.Monoid
import Data.String

import Network.Wai.Middleware.RequestLogger

import Web.Scotty

data FullName = FullName { firstName :: String, lastName :: String }

lastFirst :: FullName -> String
lastFirst fn = lastName fn ++ ", " ++ firstName fn

main = scotty 3000 $ do
    middleware logStdoutDev

    get "/" $ do
        html "<h1>Hello World</h1>"

    get "/:x" $ do
        x <- param "x"
        html $ "<h1>" <> fromString (show x) <> " + 54 = "
                      <> fromString (show (x+(54::Int))) <> "</h1>"

    get "/:word" $ do
        w <- param "word"
        html $ "<h1>Hello " <> w <> "</h1>"

    get "/lastfirst/:fn/:ln" $ do
        fullName <- FullName <$> param "fn" <*> param "ln"
        html $ fromString (lastFirst fullName)

Scotty - Typed Captures

Routes only match if the capture can be parsed at the correct type.

{-# LANGUAGE OverloadedStrings #-}

import Web.Scotty

import Data.String

main = scotty 3000 $ do
    get "/:x" $ do
        x <- param "x"
        text $ fromString $ show $ x + (54::Int)

    get "/:word" $ do
        word <- param "word"
        text $ fromString $ "you said: " ++ word

Scotty - Warp Speed

We can take advantage of Haskell's performance.

Speed of Warp
Speed of Warp
Left graph: http://www.yesodweb.com/blog/2011/03/preliminary-warp-cross-language-benchmarks
Right graph: http://www.yesodweb.com/blog/2012/11/warp-posa

Blank Canvas

Pong Screenshot

Pong Screenshot

Try Scotty

cabal update
cabal install scotty