如何将 HTTP 请求参数传递给 quickQuery?

How to pass HTTP request parameter to quickQuery?

我正在使用 Happstack 从 HTTP 请求接收一些参数,然后将这些参数传递给一个函数,该函数将从数据库中检索数据,并且 return HTTP 响应中的数据如下:

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

但是当我构建上面的代码时,出现以下错误:

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

阅读类似问题(如 this one)后,我想我必须在某处包含 HasRqData 约束,但我不知道在哪里以及如何。

你可能已经猜到了,这也是 monad 的问题。在 happstack 中有 handful 个(HasRqData,等等),因此您可能认为这是一个复杂的案例。

让我们从 innocent-looking look 函数开始。

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

的确,有一个 non-trivial 约束 HasRqData。让我们问问自己:what monads HaveRqData? (碰巧 IO 没有!)

class HasRqData m where
...

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

其他实例是前两个实例的衍生,所以,看来我们必须首先考虑这两个选项。

  • RqData 的作用有限——你只能做 look 及其派生,从手头的请求中提取信息。因为我们还想有其他效果——查询数据库,其中之一——这对我们来说还不够。
  • ServerPartT m是同ServerPart ≡ ServerPartT IO的一般形式。正好它也HasRqData。这不是巧合,而是 happstack 设计的暗示——看起来作者的意思是我们在任何地方都使用这个单一的 monad,除非我们需要特定的粒度。那么,让我们试一试吧。

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

这编译。

现在,我们甚至不需要在 handlers 中提升 myFunc — 我们之前讨论过的 solved itself. We will need to lift our access to the database though, by the same

我相信你可以自己想出细节。无论如何,让我知道结果如何!