1WAI: Web Application Interface 2============================== 3 4Getting started 5--------------- 6 7You want a minimal example? Here it is! 8 9~~~ {.haskell} 10{-# LANGUAGE OverloadedStrings #-} 11import Network.Wai 12import Network.HTTP.Types 13import Network.Wai.Handler.Warp (run) 14 15app :: Application 16app _ respond = do 17 putStrLn "I've done some IO here" 18 respond $ responseLBS 19 status200 20 [("Content-Type", "text/plain")] 21 "Hello, Web!" 22 23main :: IO () 24main = do 25 putStrLn $ "http://localhost:8080/" 26 run 8080 app 27~~~ 28 29Put that code into a file named _hello.hs_ and install [wai] and [warp] from Hackage: 30 31 cabal install wai warp 32 33Run it: 34 35 runhaskell hello.hs 36 37Point your browser to: 38 39 http://localhost:8080/ 40 41 42Serving static content 43---------------------- 44 45We can modify our previous example to serve static content. For this create a file named _index.html_: 46 47 <p>Hello, Web!</p> 48 49Now we redefine `responseBody` to refer to that file: 50 51~~~ {.haskell} 52app2 :: Application 53app2 _ respond = respond index 54 55index :: Response 56index = responseFile 57 status200 58 [("Content-Type", "text/html")] 59 "index.html" 60 Nothing 61~~~ 62 63 64Basic dispatching 65----------------- 66 67An `Application` maps `Request`s to `Response`s: 68 69 ghci> :info Application 70 type Application = Request -> (Response -> IO ResponseReceived) -> IO ResponseReceived 71 72Depending on the path info provided with each `Request` we can serve different `Response`s: 73 74~~~ {.haskell} 75app3 :: Application 76app3 request respond = respond $ case rawPathInfo request of 77 "/" -> index 78 "/raw/" -> plainIndex 79 _ -> notFound 80 81plainIndex :: Response 82plainIndex = responseFile 83 status200 84 [("Content-Type", "text/plain")] 85 "index.html" 86 Nothing 87 88notFound :: Response 89notFound = responseLBS 90 status404 91 [("Content-Type", "text/plain")] 92 "404 - Not Found" 93~~~ 94 95 96Doing without overloaded strings 97-------------------------------- 98 99For the sake of efficiency, WAI uses the [bytestring] package. We used GHCs [overloaded strings] to almost hide this fact. But we can easily do without. What follows is a more verbose definition of `notFound`, that works without GHC extensions: 100 101~~~ {.haskell .ignore} 102import qualified Data.ByteString.Char8 as B8 103import qualified Data.ByteString.Lazy.Char8 as LB8 104import Data.CaseInsensitive (mk) 105 106notFound = responseLBS 107 status404 108 [(mk $ B8.pack "Content-Type", B8.pack "text/plain")] 109 (LB8.pack "404 - Not Found") 110~~~ 111 112 113 [wai]: http://hackage.haskell.org/package/wai 114 [warp]: http://hackage.haskell.org/package/warp 115 [overloaded strings]: http://www.haskell.org/ghc/docs/latest/html/users_guide/type-class-extensions.html#overloaded-strings 116 [bytestring]: http://hackage.haskell.org/package/bytestring 117