packages feed

happs-tutorial-0.8: templates/moreserver.st

<h3>More examples of using Happstack.Server</h3>
<p>There are a number of basic combinators provided by Happstack.Server and Happstack.Helpers that allow us to create an arbitrarily complicated structure to handle requests.</p>
<p>The functions we'll discuss in this section are:  </p>
<ul>
  <li> dir
  <li> exactdir
  <li> method
  <li> fileServ
</ul>
<p>We'll also discuss the utility of the standard instances of ServerPartT</p>

<h4>dir and exactdir</h4>
<p>Entire the following into ghci:  
<br>ghci>:m + Happstack.Server
<br>ghci>let h1 = dir "snack" [return "ham"] :: ServerPartT IO String
<br>ghci>simpleHTTP (Conf 8080 Nothing) [h1]
</p>
<p>Now try navigating to "localhost:8080".  You should get an error that there is no handler.</p>
<p>Now try navigating to "localhost:8080/snack".  You should get the text "ham".</p>
<p>Now for one last test try "localhost:8080/snack/stuff".  What happens?</p>
<p>Cool, huh?  Now let's try using the exactdir method from Happstack.Helpers instead.  $! need to do something about ghci and the need to restart it !$
<br>ghci>:m + Happstack.Helpers
<br>ghci>let h2 = exactdir "/foo" [return "bar"] :: ServerPartT IO String
<br>ghci>simpleHTTP (Conf 8080 Nothing) [h2]
</p>
<p>Now try navigating to "localhost:8080/foo".  Works exactly as you'd expect, right?  What happens if you navigate to "localhost:8080/foo/fud" instead?</p>
<h4>ServerPartT as a Monoid</h4>
<p>Interrupt simpleHTTP again and let us try something slightly different.
<br>ghci>:m + Data.Monoid
<br>ghci>let h3 = h1 `mappend` h2
<br>ghci>simpleHTTP (Conf 8080 Nothing) [h3]
</p>
<p>
There's a caveat to remember, though, related to the Monoid
instance for ServerPartT.  Try this:  
<br>ghci>let h4 = dir "snack" [return "ham2"]
<br>ghci>simpleHTTP (Conf 8080 Nothing) [h4 `mappend` h1] 
</p>
<p>You should see ham2 if you navigate to localhost:8080/snack.  That's because the <strong>first</strong> handler that can handle a request is the one that is chosen.</p>
<p>You can probably guess what mempty does for ServerPartT in order for the Monoid instance to make sense.  It's the handler that cannot handle any requests.</p>
<p>One last point is that the Monoid and MonadPlus instances for ServerPartT will have the same behavior.  In this tutorial I will favor the use of Monoid over MonadPlus for entirely arbitrary reasons.</p>
<h4>method and Method</h4>
<p>Every request will have a Method.  This Method corresponds to the actual HTTP method of request.  As you can imagine, that means that Method is an algebraic data type.  Go ahead and try typing :i Method into ghci.  You should see
<br>data Method
<br>  = GET | HEAD | POST | PUT | DELETE | TRACE | OPTIONS | CONNECT
</p>
<p>When we've been creating ServerPartTs using return, the result is a handler that accepts requests with any type of method.  As you can imagine, Happstack.Server includes a functions that can limit a handler to only responding to certain Methods.  They are appropriately called method and methodSP.  Check their types in ghci.
<br>ghci>:t method
<br>method :: (Happstack.Server.SimpleHTTP.MatchMethod method,Monad m) =>
<br>method -> WebT m a -> ServerPartT m a
<br>:t methodSP
<br>methodSP :: (Happstack.Server.SimpleHTTP.MatchMethod method, Monad m) => 
<br>method -> ServerPartT m a -> ServerPart m a
</p>
<p>Now those might seem like very odd types, but they're simpler than they look.  You can pass a literal Method, a list of Methods, or a predicate on Methods for them to make their selection.  I'm going to use methodSP in the sequel because I find it more clear to use ServerPartTs as an opaque type rather than dealing with WebTs directly.</p>
<p>To test out these functions, try using the two forms below.</p>
<form name="getinput" action="/getformhandler"
 method="get">
  <input type="text" name="input">
  <input type="submit" value="Submit">
</form>

<form name="postinput" action="/postformhandler"
  method="post">
   <input type="text" name="input">
   <input type="submit" value="Submit">
</form>