happs-tutorial 0.8.1 → 0.9.0
raw patch · 6 files changed
+168/−16 lines, 6 filesdep ~DebugTraceHelpersdep ~HStringTemplatedep ~HStringTemplateHelpers
Dependency ranges changed: DebugTraceHelpers, HStringTemplate, HStringTemplateHelpers, HTTP, bytestring, containers, directory, filepath, happstack, happstack-data, happstack-helpers, happstack-ixset, happstack-server, happstack-state, hscolour, mtl, old-time, parsec, pretty, pureMD5, safe
Files
- happs-tutorial.cabal +24/−6
- src/GetExample.hs +83/−0
- src/HSPExample.hs +31/−0
- templates/formsanddata.st +23/−0
- templates/getandpost.st +5/−5
- templates/whatsnew.st +2/−5
happs-tutorial.cabal view
@@ -1,5 +1,5 @@ Name: happs-tutorial-Version: 0.8.1+Version: 0.9.0 Synopsis: A Happstack Tutorial that is its own web 2.0-type demo. Description: A nice way to learn how to build web sites with Happstack @@ -46,10 +46,28 @@ MiscMap ControllerStressTests View- ghc-options: -Wall- Build-Depends: base, HStringTemplate, HStringTemplateHelpers, mtl, bytestring,- happstack, containers, pretty, pureMD5, directory, filepath, hscolour, - HTTP, safe, old-time, parsec, happstack-helpers, DebugTraceHelpers,- happstack-server, happstack-data, happstack-ixset, happstack-state+ ghc-options: -Wall -O2+ Build-Depends: base+ , HStringTemplate >= 0.4.0 && < 0.5.0+ , HStringTemplateHelpers > 0.0.0 && < 1.0.0+ , mtl >= 1.1.0.0 && < 2.0.0.0 + , bytestring >= 0.9.0.0 && < 0.10.0.0+ , happstack >= 0.3 && < 0.4+ , containers >= 0.2.0.0 && < 0.3.0.0+ , pretty >= 1.0.1.0 && < 2 + , pureMD5 >= 1.0.0.0 && < 1.1.0.0+ , directory >= 1.0.0.0 && < 1.1.0.0+ , filepath >= 1.1.0.0 && < 1.2.0.0+ , hscolour >= 1.0 && < 2.0+ , HTTP >= 4000.0.7 && < 4000.0.8+ , safe >= 0.2 && < 0.3+ , old-time >= 1.0.0.0 && < 1.1.0.0+ , parsec >= 2.1.0.0 && < 2.2.0.0+ , happstack-helpers >= 0.30 && < 0.40+ , DebugTraceHelpers >= 0.12 && < 0.20+ , happstack-server >= 0.3 && < 0.4+ , happstack-data >= 0.3 && < 0.4+ , happstack-ixset >= 0.3 && < 0.4+ , happstack-state >= 0.3 && < 0.4 if flag(base4) Build-Depends: base >=4 && <5, syb
+ src/GetExample.hs view
@@ -0,0 +1,83 @@+{-# OPTIONS_GHC -F -pgmFtrhsx #-}++import Happstack.Server+import HSP+import Happstack.Server.HSP.HTML+import Data.Monoid++{- We define a very simple data type here to use as our+ instance for FromData -}+data Foo = Foo {bar :: Int,+ baz :: Int}+ deriving Show++{- Defining an instance of FromData is fundamentally simple. Primarily, you should use the helper function look+to grab the string associated with the named parameter you provide. From there, we use read to parse the string into an+int and return the final Foo. This isn't the safest construction, because the read could fail, but you can easily provide+yourself with more safety by using the MonadPlus instance of RqData and just calling mzero when an error occurs.-}+instance FromData Foo where+ fromData = do+ x <- read `fmap` look "bar"+ y <- read `fmap` look "baz"+ return $ Foo x y++main :: IO ()+main = simpleHTTP nullConf{port=8080} $ (dir "getHandler" handler) `mappend` (dir "postHandler" handler) `mappend` home++{- Please note that we actually use the same handler for both GET & POST requests. + This is an advantage of using FromData.+-}+handler :: ServerPartT IO Response+handler = do+ mfoo <- getData+ case mfoo of+ Nothing -> webHSP $ didn'twork+ Just foo -> webHSP $ displayFoo foo++displayFoo :: Foo -> HSP XML+displayFoo f = <html>+ <head>+ <title>This is a Foo</title>+ </head>+ <body>+ <p>Here, look at a Foo: <%show f%></p>+ <p><a href="/">home</a></p>+ </body>+ </html>++didn'twork = <html>+ <head>+ <title>Something is wrong!</title>+ </head>+ <body>+ <p>Something has gone horribly wrong+ <a href="/">go home</a></p>+ </body>+ </html>++home :: ServerPartT IO Response+home = webHSP $ <html>+ <head>+ <title>Get and Post examples</title>+ </head>+ <body>+ <form action="getHandler" method="GET">+ <p>+ <label for="bar">Bar: </label>+ <input type="text" name="bar" /><br/>+ <label for="baz">Baz: </label>+ <input type="text" name="baz" /><br/>+ <input type="submit" value="Send" />+ </p>+ </form>+ <form action="postHandler" method="POST">+ <p>+ <label for="bar">Bar: </label>+ <input type="text" name="bar" /><br/>+ <label for="baz">Baz: </label>+ <input type="text" name="baz" /><br/>+ <input type="submit" value="Send" />+ </p>+ </form>+ </body>+ </html>
+ src/HSPExample.hs view
@@ -0,0 +1,31 @@+{-# OPTIONS_GHC -F -pgmFtrhsx #-}+-- You might be wondering what's the point of this options declaration. +-- It enables a particular preprocessor that allows the literal HTML syntax+-- for HSP. Without it this example cannot compile.++import Happstack.Server+import Happstack.Server.HSP.HTML+import HSP+import System.Random++main :: IO ()+main = simpleHTTP nullConf{port=8080} home++{- Integrating HSP into Happstack is very simple. One just lifts the HSP value into a ServerPartT with webHSP from+ Happstack.Server.HSP.HTML -}+home :: ServerPartT IO Response+home = webHSP $ <html>+ <head>+ <title>Simple HSP w/ Happstack Example</title>+ </head>+ <body>+ <h1>HSP can be convenient</h1>+ <ol>+ <li>You can include your html in your Haskell file exactly as you'd expect.</li>+ <li>You can include <%"haskell values"%> very easily in your code.</li>+ <li>Or even IO actions: <%aux%>.</li> + <li>Your HTML is parsed and built at compile time, so that is where mistakes are caught</li>+ </ol>+ </body>+ </html>+ where aux = doIO $ show `fmap` randomRIO (0,100 :: Int)
+ templates/formsanddata.st view
@@ -0,0 +1,23 @@+<h3>GET, POST, and FromData</h3>+<p>We've covered how to serve basic HTML with Happstack, in a number of different ways. What we haven't yet covered+is what to do with form data. In principle, you could dig into the request and try to pull out the parameters. That's+not the Happstack way, though.</p>+<p>Instead, you can use the type class FromData and the functions getData and withData.+A simple example can be found in <a href=/src/GetExample.hs>GetExample.hs<a/>. This example uses HSP to build+the forms, for simple convenience.</p>+<p>ghci>:i FromData+<br/>class FromData a where fromData :: RqData a+<br/> -- Defined in Happstack.Server.SimpleHTTP+<br/>instance [overlap ok] (FromData a, FromData b) => FromData (a, b)+<br/> -- Defined in Happstack.Server.SimpleHTTP+<br/>instance [overlap ok] (FromData a, FromData b, FromData c) => FromData (a, b, c)+<br/> -- Defined in Happstack.Server.SimpleHTTP+<br/>instance [overlap ok] (FromData a,FromData b,FromData c,FromData d) => FromData (a, b, c, d)+<br/> -- Defined in Happstack.Server.SimpleHTTP+<br/>instance [overlap ok] (FromData a) => FromData (Maybe a)+<br/> -- Defined in Happstack.Server.SimpleHTTP+</p>+<p>An important note about RqData is that it is a Monad and a MonadPlus, so between this type class machinery and+the helper function look, you should be able to define your own instances of FromData for your own types.+Again, the simple example up above should provide some guidance for this.</p>+<p>Next we cover <a href="/tutorial/file-uploads">uploading files</a></p>
templates/getandpost.st view
@@ -2,18 +2,18 @@ <p>GET data is data attached to an http request via the url string. In the job board app, an example of this is <a href=/tutorial/viewprofile?user=tphyahoo>tphyahoo's profile</a>, where the user is specified on the url string.- Another example is <a href=/tutorial/viewjob?user=tphyahoo&job=darcshub>fetching a particular job</a>.+ Another example is <a href=/tutorial/viewjob?user=tphyahoo&job=darcshub>fetching a particular job</a>.</p> <p>POST data is data attached to a request after submitting a form. One place this is used is in the <a href=/tutorial/register>registration</a> process.- Once you have a user created, you can also see POST in action by editing your profile or creating jobs.+ Once you have a user created, you can also see POST in action by editing your profile or creating jobs.</p> -<p>Happstack deals with GET and POST data similarly.+<p>Happstack deals with GET and POST data similarly.</p> <p>Let's look at how- <a href=/tutorial/viewprofile?user=tphyahoo>tphyahoo's profile</a> gets displayed.+ <a href=/tutorial/viewprofile?user=tphyahoo>tphyahoo's profile</a> gets displayed.</p> -<p><a href=/src/Controller.hs>Controller.hs</a>: ... , dir "viewprofile" [ methodSP GET \$ userProfile rglobs ] ...+<p><a href=/src/Controller.hs>Controller.hs</a>: ... , dir "viewprofile" [ methodSP GET \$ userProfile rglobs ] ...</p> <p>using dir and methodSP as above is a common pattern. dir pops the head element of the path array ["viewprofile"], resulting in an empty array. methodSP checks that the path array is empty and that
templates/whatsnew.st view
@@ -1,7 +1,4 @@-<h3>What's new in version 0.8.1</h3>+<h3>What's new in version 0.9.0</h3> <ul>-<li>New section on IxSets</li>-<li>Simplified migration examples</li>-<li>General cleanups of the tutorial code</li>-<li>Using random numbers in Updates and Queries in MACID intro</li>+<li>Compatibility with new Happstack 0.3.*</li> </ul>