如何使用 scotty 从 sqlite 和响应 json 获取数据?
How to get data from sqlite and response json using scotty?
我正在尝试使用 Haskell 和框架 Scotty 构建一个简单的博客。使用 Model.hs 我有:
data Post = Post
{ id :: Int
, tipo :: String
, titulo :: String
, conteudo :: String
} deriving (Show, Generic)
我已经使用 sqlite 创建了一个模式并填充了一些数据,现在我正尝试在我的 Storage.hs
中使用这个方法获取这些数据
selectPosts :: Sql.Connection -> IO [M.Post]
selectPosts conn =
Sql.query_ conn "select * from post" :: IO [M.Post]
我的目的是在我的 Main.hs:
中获取 json 的数据格式
instance ToJSON M.Post
instance FromJSON M.Post
main :: IO ()
main = do
putStrLn "Starting Server..."
scotty 3000 $ do
get "/" $ file "templates/index.html"
get "/posts" $ do
json posts where
posts = withTestConnection $ \conn -> do
S.selectPosts conn
但是我得到了一个 IO [模型 Post],我不知道如何将其呈现为 json,所以它一直收到此错误:
No instance for (ToJSON (IO [Post])) arising from a use of ‘json’
我的项目在 github 到 运行 之间,只使用堆栈构建和堆栈 ghci 之后。在建筑物中,我已经收到此错误。
在 Haskell 中,所有函数都是纯函数——所以像 selectPosts
这样的东西,它需要出去做 IO 来与数据库对话,不能只是那样做 return 来自数据库的值。相反,这些类型的函数 return 类型 IO a
的东西,你可以认为它基本上是对如何出去并进行 IO 以获得类型 a
的值的描述。这些"IO actions"可以组合在一起,其中一个可以赋值给main
;在运行时,RTS 将执行这些 IO 操作。
但是,您并没有将从 selectPosts
返回的 IO a
值组合成最终变为 main
的较大 IO
值的一部分;您正试图通过将其输入 json
来直接使用它。这行不通,因为没有 (good/easy) 方法可以将如何执行 IO 的描述转换为 JSON 字符串。
Haskell 处理组合这些值的方式是通过称为 "monad" 的抽象,这在许多其他情况下也很有用。 do
符号可用于以非常自然的方式编写此单子序列。您不能在这里只写 posts <- withTestConnection S.selectPosts
,因为 Scotty 的 get
函数采用 monadic ActionM
类型的值,而不是 IO
。然而,事实证明 ActionM
基本上是在 IO
之上分层的一堆其他有用的东西,所以应该可以 "lift" 来自 selectPosts
的 IO 操作Scotty 的 ActionM
monad:
get "/posts" $ do
posts <- liftIO $ withTestConnection S.selectPosts
json posts
旁注:您可能已经注意到我写了 withTestConnection S.selectPosts
而不是 withTestConnection $ \conn -> do S.selectPosts conn
。通常,如果您有一个 do
块,其中只有一个表达式(不是 x <- act
的形式),这与 do
块外的单个表达式相同:\conn -> S.selectPosts conn
。此外,Haskell 倾向于鼓励部分应用:你有 S.selectPosts
,这是一个函数 Sql.Connection -> IO [M.Post]
。 \conn -> S.selectPosts conn
是另一个相同类型的函数,它将连接传递给 selectPosts
然后 returns 与 selectPosts
相同的结果---这个函数与 selectPosts
本身!因此,如果这就是您 withTestConnection
中所需的全部内容,您应该能够将整个 lambda 和 do
块简化为 S.selectPosts
。
我正在尝试使用 Haskell 和框架 Scotty 构建一个简单的博客。使用 Model.hs 我有:
data Post = Post
{ id :: Int
, tipo :: String
, titulo :: String
, conteudo :: String
} deriving (Show, Generic)
我已经使用 sqlite 创建了一个模式并填充了一些数据,现在我正尝试在我的 Storage.hs
中使用这个方法获取这些数据selectPosts :: Sql.Connection -> IO [M.Post]
selectPosts conn =
Sql.query_ conn "select * from post" :: IO [M.Post]
我的目的是在我的 Main.hs:
中获取 json 的数据格式instance ToJSON M.Post
instance FromJSON M.Post
main :: IO ()
main = do
putStrLn "Starting Server..."
scotty 3000 $ do
get "/" $ file "templates/index.html"
get "/posts" $ do
json posts where
posts = withTestConnection $ \conn -> do
S.selectPosts conn
但是我得到了一个 IO [模型 Post],我不知道如何将其呈现为 json,所以它一直收到此错误:
No instance for (ToJSON (IO [Post])) arising from a use of ‘json’
我的项目在 github 到 运行 之间,只使用堆栈构建和堆栈 ghci 之后。在建筑物中,我已经收到此错误。
在 Haskell 中,所有函数都是纯函数——所以像 selectPosts
这样的东西,它需要出去做 IO 来与数据库对话,不能只是那样做 return 来自数据库的值。相反,这些类型的函数 return 类型 IO a
的东西,你可以认为它基本上是对如何出去并进行 IO 以获得类型 a
的值的描述。这些"IO actions"可以组合在一起,其中一个可以赋值给main
;在运行时,RTS 将执行这些 IO 操作。
但是,您并没有将从 selectPosts
返回的 IO a
值组合成最终变为 main
的较大 IO
值的一部分;您正试图通过将其输入 json
来直接使用它。这行不通,因为没有 (good/easy) 方法可以将如何执行 IO 的描述转换为 JSON 字符串。
Haskell 处理组合这些值的方式是通过称为 "monad" 的抽象,这在许多其他情况下也很有用。 do
符号可用于以非常自然的方式编写此单子序列。您不能在这里只写 posts <- withTestConnection S.selectPosts
,因为 Scotty 的 get
函数采用 monadic ActionM
类型的值,而不是 IO
。然而,事实证明 ActionM
基本上是在 IO
之上分层的一堆其他有用的东西,所以应该可以 "lift" 来自 selectPosts
的 IO 操作Scotty 的 ActionM
monad:
get "/posts" $ do
posts <- liftIO $ withTestConnection S.selectPosts
json posts
旁注:您可能已经注意到我写了 withTestConnection S.selectPosts
而不是 withTestConnection $ \conn -> do S.selectPosts conn
。通常,如果您有一个 do
块,其中只有一个表达式(不是 x <- act
的形式),这与 do
块外的单个表达式相同:\conn -> S.selectPosts conn
。此外,Haskell 倾向于鼓励部分应用:你有 S.selectPosts
,这是一个函数 Sql.Connection -> IO [M.Post]
。 \conn -> S.selectPosts conn
是另一个相同类型的函数,它将连接传递给 selectPosts
然后 returns 与 selectPosts
相同的结果---这个函数与 selectPosts
本身!因此,如果这就是您 withTestConnection
中所需的全部内容,您应该能够将整个 lambda 和 do
块简化为 S.selectPosts
。