database - 如何将数据库连接传递给我的 http 处理程序?

标签 database haskell scope monads

这是我的 REST API 的简化版本。我正在使用 ScottyRethinkDB .

现在我必须将数据库连接传递给每个路由处理程序,以便它们可以运行 查询(参见coursesAll)。如果有超过 10 条路线,这将变得非常烦人。我知道我可以在 main 方法中定义路由处理程序,并且连接句柄 h 将在范围内,但这也无法扩展。

我希望能够定义顶级函数,这样我就可以将它们放在不同的文件中。我怎样才能清理这段代码?

我大脑的一部分知道 monad 可以做到这一点,但是怎么做呢? Scotty 使用 ActionM monad,RethinkDB 也有一个 monad,但我不确定如何组合它们。

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}

import Web.Scotty
import Courses.Course
import qualified Database.RethinkDB as R
import Control.Monad.IO.Class (liftIO)
import Courses.Connection

main :: IO ()
main = do
    h <- connectDb
    scotty 3000 $ do
        get "/" info
        get "/courses" (coursesAll h)

info :: ActionM ()
info = text "Courses v1"

coursesAll :: R.RethinkDBHandle -> ActionM ()
coursesAll h = do
    courses <- liftIO $ R.run h coursesTable
    json $ (courses :: [Course])


connectDb :: IO (R.RethinkDBHandle)
connectDb = do
    connection <- R.connect "localhost" 28015 Nothing
    let connectionDb = R.use connection (R.db "courses")
    return connectionDb

更新:RethinkDB 最终变得不相关。真的,我想知道如何将全局配置传递到我的路由中。例如:

{-# LANGUAGE OverloadedStrings #-}

import qualified Web.Scotty
import Web.Scotty.Trans

import Data.Text.Lazy
import Control.Monad.IO.Class (liftIO)

import Control.Monad.Trans.Reader
import Control.Monad.Trans

data Config = Config Text

main :: IO ()
main = do
    let config = Config "Hello World"
    -- how to I make this line work?
    scottyT 3000 id id routes

routes :: ScottyT Text (ReaderT Config IO) ()
routes = do
    get "/" info

info :: ActionT Text (ReaderT Config IO) ()
info = do
    -- this part seems like it works!
    Config message <- lift ask
    text $ "Info: " `append` message

最佳答案

您几乎已经完成了更新后的问题,您唯一需要做的就是为 scottyT 提供两个运行器函数。 .那么让我们看看签名

scottyT 
  :: (Monad m, MonadIO n)    
  => Port    
  -> (forall a. m a -> n a) 
  -> (m Response -> IO Response)    
  -> ScottyT e m ()  
  -> n ()

m是要嵌入到 ActionT 中的 monad堆栈和n是你运行时想要的结果 monad scottyT .

在你的情况下 mReaderT Config IOn就是IO .

函数(forall a. m a -> n a)是一个转换任何 ReaderT Config IO a 的函数计算成IO a我们可以很容易地用 runReaderT 做到这一点.所以让我们定义

let readerToIO ma = runReaderT ma config

接下来我们需要一个函数来转换m ResponseIO Response但因为在这种情况下 nIO相同我们可以重用上面的 readerToIO功能。因此

main = do
    let config = Config "Hello World"
        readerToIO ma = runReaderT ma config
    scottyT 3000 readerToIO readerToIO routes

关于database - 如何将数据库连接传递给我的 http 处理程序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26048015/

相关文章:

模块中的javascript私有(private)内部函数可以访问 "this"范围

Haskell "dependent"记录字段?

haskell - 如何横向和向下 build 一棵树?

multithreading - 如果与 `putChar` > 1 秒一起使用,Haskell 的 `threadDelay` 不会打印任何内容

javascript - 如何从模型存储 EXTJ 中读取额外的属性?

即使使用了 global 关键字,PHP 全局变量在函数内部也是未定义的

mysql - 继承相同的 N :M table for different associations

android - 游标遍历空行

mysql - 如何访问我新设置的 MySQL 数据库(获取 "Domain is currently unable to handle this request.")

php - 我需要在更新 MYSQL 中的表后返回受影响行的主键。