[started documentation new RqData Jeremy Shaw **20100712182926 Ignore-this: c7fe1b872836d20151a348bce1f16315 ] addfile ./HelloRqData.lhs hunk ./HelloRqData.lhs 1 + + +

Hello RqData

+ +

Let's start with a simple hello, world! example that is parameterized using the request parameters.

+
+ +> module Main where +> +> import Happstack.Server (ServerPart, nullConf, simpleHTTP, ok) +> import Happstack.Server.RqData (BodyPolicy, RqData, look, withDataFn, defaultBodyPolicy) +> +> myPolicy :: BodyPolicy +> myPolicy = defaultBodyPolicy "/tmp" 0 1024 4096 +> +> helloRq :: RqData (String, String) +> helloRq = +> do g <- look "greeting" +> n <- look "noun" +> return (g, n) +> +> helloPart :: ServerPart String +> helloPart = +> withDataFn myPolicy helloRq $ \(greet, noun) -> +> ok $ greet ++ ", " ++ noun +> +> main :: IO () +> main = simpleHTTP nullConf $ helloPart + +
+

[Source code for the app is here.]

+

Now if we visit http://localhost:8000/?greeting=hello&noun=rqdata, we will get the message hello, rqdata

+ +

First we define a policy which limits the amount of data a client is allowed to send. We will cover policy creation in more detail later. But for now we will just use the default policy which takes four arguments:

+
    +
  1. directory for temporary files
  2. +
  3. maximum amount of disk space allowed for file uploads
  4. +
  5. maximum amount of bytes allow for values that will be stored in RAM
  6. +
  7. maximum amount of bytes allowed in request body headers
  8. +
+ +

For this example, we are not going to allow file uploads, so we set the disk quota to zero bytes.

+
+#ifdef HsColour +> +> myPolicy :: BodyPolicy +> myPolicy = defaultBodyPolicy "/tmp" 0 1024 4096 +> +#endif +
+ +

Next we define a function which will look up the values of the keys greeting and noun.

+ +
+#ifdef HsColour +> helloRq :: RqData (String, String) +> helloRq = +> do g <- look "greeting" +> n <- look "noun" +> return (g, n) +> +#endif +
+ +

In the above code, we are using the Monad instance for RqData. There is also an Applicative Functor instance, which is covered more in the error reporting section. The Monad instance is easier to use, but the Applicative Functor can provide better error messages.

+ +

In helloRq we use the look function to look up some keys by name. The look function has the type:

+ +
+#ifdef HsColour +> look :: String -> RqData String +#endif +
+ +

The look function looks up a key and decodes the associated value as a String. It assumes the underlying ByteString was utf-8 encoded. If you are using some other encoding, then you can use lookBS to construct your own lookup function.

+ +

If the key is not found, then lookup will fail. Since we are using the Monad instance for RqData, that means the whole RqData will fail.

+ +

In this ServerPart we actually use myPolicy and helloRq via withDataFn:

+ +
+#ifdef HsColour +> helloPart :: ServerPart String +> helloPart = +> withDataFn myPolicy helloRq $ \(greet, noun) -> +> ok $ greet ++ ", " ++ noun +#endif +
+ +

withDataFn has the type:

+ +
+#ifdef HsColour +> withDataFn :: (MonadIO m, MonadPlus m, ServerMonad m) => BodyPolicy -> RqData a -> (a -> m r) -> m r +> -- simplified type when m == ServerPart +> withDataFn :: BodyPolicy -> RqData a -> (a -> ServerPart r) -> ServerPart r +#endif +
+ +

withDataFn takes care of retrieving and decoding the cookies, QUERY_STRING, and request body, running the RqData to extract the desired values, and then passing the values to the handler that uses them. In this example, the handler just takes the tuple, and constructs a simple String response.

+ +

If the RqData fails (because the required values are not found), then withDataFn will fail as well, and the next handler will be tried. We do not have any more handlers in this example, so the server will return a generic 404 page. If we want to have more control of what happens with RqData fails we could use getDataFn instead:

+ +
+#ifdef HsColour +> getDataFn :: (ServerMonad m, MonadIO m) => BodyPolicy -> RqData a -> m (Either [String] a) +> -- simplified type when m == ServerPart +> getDataFn :: BodyPolicy -> RqData a -> ServerPart (Either [String] a) +#endif +
+ +

getDataFn returns either a list of errors, or the succesfully extracted value. It is covered in more detail in the RqData error handling section.

+ hunk ./Makefile 5 -DEPS := HelloWorld.lhs RouteFilters.lhs Templates.lhs -ROUTE_FILTER_DEPS := MonadPlus.lhs Dir.lhs Dir2.lhs Dirs.lhs Path.lhs FromReqURI.lhs MethodM.lhs MatchMethod.lhs +DEPS := HelloWorld.lhs RouteFilters.lhs Templates.lhs RqData.lhs +HELLOWORLD_DEMOS := HelloWorld.lhs +ROUTE_FILTER_DEMOS := MonadPlus.lhs Dir.lhs Dir2.lhs Dirs.lhs Path.lhs FromReqURI.lhs MethodM.lhs MatchMethod.lhs +RQDATA_DEPS := +RQDATA_DEMOS := HelloRqData.lhs +DEMOS := $(RQDATA_DEMOS) $(ROUTE_FILTER_DEMOS) $(HELLOWORLD_DEMOS) hunk ./Makefile 19 +RqData.html: $(RQDATA_DEPS) $(RQDATA_DEMOS) hunk ./Makefile 22 + mkdir -p html/theme addfile ./RqData.lhs hunk ./RqData.lhs 1 + + + + Crash Course in Happstack + + + + + +

Back to Table of Contents

+

Parsing request data from the QUERY_STRING, cookies, and request body

+

The contents of this section are based on the development version of Happstack which includes new functionality and a slightly different API.

+ +

The RqData module is used to extract key/value pairs from the QUERY_STRING, cookies, and the request body of a POST or PUT request.

+ +#include "HelloRqData.lhs" hunk ./theme.css 169 +.warning +{ + color: red; + } +