Ahmad Ibrahim
Ahmad Ibrahim

Reputation: 1925

How to pass HTTP request parameter to quickQuery?

I'm using Happstack to receive some parameters from an HTTP request then pass these parameters to a function that will retrieve data from the database and return this data in the HTTP response as follow:

myFunc :: IO String
myFunc = do r <- look "personId"
            conn <- connectODBC "... my connection string ...";
            vals <- quickQuery conn ("SELECT Name FROM Person where Id = ?") [(toSql r)];
            return (processData vals)

handlers :: ServerPartT IO Response
handlers = do
       x <- liftIO (myFunc);
       decodeBody (defaultBodyPolicy "/tmp/" 0 1000 1000)
       msum [ 
              dir "getData" $ ok $ toResponse x
            , ... other handlers ...
            ]

mainFunc = simpleHTTP nullConf handlers

But when I build the above code I get the following error:

No instance for (HasRqData IO) arising from a use of `look' In a stmt of a 'do' block: r <- look "personId"

After reading questions on similar issues (like this one) I think I have to include HasRqData constraint somewhere, but I couldn't learn where and how.

Upvotes: 1

Views: 138

Answers (1)

Ignat Insarov
Ignat Insarov

Reputation: 4832

As you may have guessed, this is too an issue with monads. There are a handful of them in happstack (HasRqData, among others), so you may well consider it a complicated case.

Let us begin with the innocent-looking look function.

look :: (Functor m, Monad m, HasRqData m) => String -> m String

Indeed, there is a non-trivial constraint HasRqData. Let us ask ourselves: what monads HaveRqData? (It so happens that IO has not!)

class HasRqData m where
...

Instances
    HasRqData RqData         
    (MonadIO m, MonadPlus m) => HasRqData (ServerPartT m)
    ...

The other instances are derivative of these first two, so, it looks like we have to consider these two options first.

  • The RqData has limited effects — you can only do look and its derivatives, extracting information from the request at hand. As we want to also have other effects — querying the database, for one, — this is not enough for us.
  • The ServerPartT m is the general form of the same old friend of ours, ServerPart ≡ ServerPartT IO. It happens that it also HasRqData. This is not a coincidence, but rather an implication of the design of happstack — looks like the authors meant us to use this single monad everywhere, unless we need particular granularity. So, let's give it a try.

 

myFunc :: ServerPart String
myFunc = do r <- look "personId"
            return undefined

This compiles.

Now, we don't even need to lift myFunc in handlers — our previous predicament solved itself. We will need to lift our access to the database though, by the same jar logic we discussed before.

I believe you can figure the details by yourself. In any case, let me know how it works out!

Upvotes: 1

Related Questions