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.
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
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.
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
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
MonadPlus which will come in handy later. We'll see this when we learn
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
Finally, the response is produced with
ok200 $ show t. As you would have guessed, this generates an HTTP
response with the body produced by
show t. We return a
String body in this case, but it can be any type