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