First Application¶
Let us build our first WebGear application. We'll start off with a simple one, the goal of our first application is to respond with the current time for every HTTP request.
Modify src/Main.hs
to contain the following code.
import Control.Monad.IO.Class
import Data.Time.Clock
import Network.Wai.Handler.Warp
import WebGear
getTime :: MonadIO m => Kleisli m a (Response String)
getTime = Kleisli $
\request -> do
t <- liftIO getCurrentTime
return $ ok200 $ show t
main :: IO ()
main = run 3000 (toApplication getTime)
Build and run the project:
stack build
stack exec webgear-guide
cabal run webgear-guide
Access http://localhost:3000 and the application should return the current UTC time.
Let us check the code in detail to understand this clearly.
WAI and Warp¶
We will first examine main
function.
Like many other Haskell web frameworks, WebGear uses WAI and Warp. WAI provides an interface for web applications to interact with web servers. Warp is a web server based on WAI.
In the main
function, toApplication
is used to convert our WebGear handler to a WAI application. This is
then passed to run
which starts a Warp server serving HTTP requests arriving at port 3000.
Handlers¶
Now we turn our attention to getTime
. This is where the business logic of our application lives. In WebGear
terminology this is called a Handler. There are a number of interesting things going on here.
First, this is a function wrapped in Kleisli
from
Control.Arrow module. These are
called Kleisli arrows which is just a fancy term for functions having the type Monad m => a -> m b
. So why don't
we use just a regular function instead of this Kleisli
wrapper? Well, it gives us some useful type class
instances such as Alternative
and MonadPlus
which will come in handy later. We'll see this when we learn
about routing.
The function inside Kleisli
takes a request value as its parameter and produces a monadic response object as its
value. We don't make use of the request in this function because we always return the current time. We also don't care
about which monad this runs under as long as it is a MonadIO
.
Finally, the response is produced with ok200 $ show t
. As you would have guessed, this generates an HTTP 200 OK
response with the body produced by show t
. We return a String
body in this case, but it can be any type
with a
ToByteString
instance.