[More documentation on RqData Jeremy Shaw **20100712232701 Ignore-this: 4d38fef506c38c0cf15f5673ebbb14a7 ] hunk ./HelloRqData.lhs 38 -

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:

+

In the code, we first 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:

hunk ./HelloRqData.lhs 116 -

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

+

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

hunk ./Makefile 8 -RQDATA_DEPS := -RQDATA_DEMOS := HelloRqData.lhs +RQDATA_DEPS := RqDataLimiting.lhs +RQDATA_DEMOS := HelloRqData.lhs RqDataError.lhs hunk ./RqData.lhs 22 +#include "RqDataError.lhs" +#include "RqDataLimiting.lhs" + + + + addfile ./RqDataError.lhs hunk ./RqDataError.lhs 1 + + +

RqData Error

+ +

If we want to have better error reporting, we can make two changes to our hello, rqdata, app:

+
    +
  1. build the query using an applicative functor instead of a monad
  2. +
  3. use getDataFn instead of withDataFn
  4. +
+ +

The following code has those two changes made:

+ +
+ +> module Main where +> +> import Control.Applicative ((<$>), (<*>)) +> import Happstack.Server (ServerPart, badRequest, nullConf, ok, simpleHTTP) +> import Happstack.Server.RqData (BodyPolicy, RqData, defaultBodyPolicy, look, getDataFn) +> +> myPolicy :: BodyPolicy +> myPolicy = defaultBodyPolicy "/tmp" 0 1024 4096 +> +> helloRq :: RqData (String, String) +> helloRq = +> (,) <$> look "greeting" <*> look "noun" +> +> helloPart :: ServerPart String +> helloPart = +> do r <- getDataFn myPolicy helloRq +> case r of +> (Left e) -> +> badRequest $ unlines ("The following request parameters are missing:" : e) +> (Right (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/, we will get the error: + +

+The following request parameters are missing:
+greeting
+noun
+
+ +

If we had used the monad functions to build the RqData instead of the applicative functor functions, then we would have only seen that the greeting was missing. Then when we added a greeting we would have gotten a new error message saying that noun was missing.

+ +

In general, improved error messages are not going to help people visiting your website. If the parameters are missing it is because a form or link they followed is invalid. There are two places where there error messages are useful:

+
    +
  1. When you are developing and debugging your site
  2. +
  3. Reporting errors to users of your web service API
  4. +
+ +

If you are providing a REST API for developers to use, they are going to be a lot happier if they get a detailed error messages instead of a plain old 404.

addfile ./RqDataLimiting.lhs hunk ./RqDataLimiting.lhs 1 + + +

Limiting lookup to QUERY_STRING or request body

+ +

By default, look and friends will search both the +QUERY_STRING the request body (aka, POST/PUT data) for a key. But +sometimes we want to specify that only the QUERY_STRING or request +body should be searched. This can be done by using the body and queryString filters:

+ +
+#ifdef HsColour +> body :: RqData a -> RqData a +> queryString :: RqData a -> RqData a +#endif +
+ +

If we want to only look in the request body we could modified helloRq to be:

+ +
+#ifdef HsColour +> helloRq :: RqData (String, String) +> helloRq = +> body ((,) <$> look "greeting" <*> look "noun") +#endif +
+ +

We could also mix and match. In this varation we look in the QUERY_STRING for the greeting and the request body for the noun

+ +
+#ifdef HsColour +> helloRq :: RqData (String, String) +> helloRq = +> (,) <$> (queryString $ look "greeting") <*> (body $ look "noun") +#endif +
+ +

queryString and body act as filters on the data that is being searched. If you were to write:

+ +
+#ifdef HsColour +> helloRq :: RqData (String, String) +> helloRq = +> body (queryString $ look "greeting") +#endif +
+ +

This RqData would never match because the body filter would hide all the QUERY_STRING values, and the queryString filter would hide all the request body values, and hence, there would be nothing left to search.

hunk ./Templates.lhs 52 - +

Next: Request parameters and data