这是我的REST API的简化版本。我正在使用Scotty和RethinkDB。
现在我必须将数据库连接传递到每个路由处理程序,以便他们可以run
查询(请参阅coursesAll
)。有超过10条路线,这真的很烦人。我知道我可以在main方法中定义路由处理程序,并且连接句柄h
将在范围内,但是它也不会缩放。
我希望能够定义顶级函数,以便将它们放在不同的文件中。如何清理此代码?
我大脑的一部分知道monads可以做到这一点,但是如何? 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
答案 0 :(得分:1)
您几乎已经知道了更新后的问题,您唯一需要的是向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
是运行scottyT
时想要的结果monad。
在您的情况下,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