这是我的 REST API 的简化版本。我正在使用 Scotty和 RethinkDB .
现在我必须将数据库连接传递给每个路由处理程序,以便它们可以运行
查询(参见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
.
在你的情况下 m
是ReaderT Config IO
和 n
就是IO
.
函数(forall a. m a -> n a)
是一个转换任何 ReaderT Config IO a
的函数计算成IO a
我们可以很容易地用 runReaderT
做到这一点.所以让我们定义
let readerToIO ma = runReaderT ma config
接下来我们需要一个函数来转换m Response
至 IO Response
但因为在这种情况下 n
与IO
相同我们可以重用上面的 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/