Haskell 在WAI中使用请求参数,但不使用;IO";引起问题
我正在努力学习如何使用WAI建立和运行API。主要问题是处理感染一切的Haskell 在WAI中使用请求参数,但不使用;IO";引起问题,haskell,web-applications,haskell-wai,Haskell,Web Applications,Haskell Wai,我正在努力学习如何使用WAI建立和运行API。主要问题是处理感染一切的IO。我相信,一旦我更好地理解单子,我的问题就会解决,但希望这个问题的答案将是一个很好的起点 下面是一个简短的示例,它在根url上提供一个静态html页面,并接受一个用户名为to/api/my data的请求,该请求应返回相应的用户数据。我不知道如何使用请求的body体的IO Bytestring执行映射查找、检索数据并将结果以json编码发送回 我曾尝试使用fmap通过testring提取,然后unpack将其转换为字符串进
IO
。我相信,一旦我更好地理解单子,我的问题就会解决,但希望这个问题的答案将是一个很好的起点
下面是一个简短的示例,它在根url上提供一个静态html页面,并接受一个用户名为to/api/my data
的请求,该请求应返回相应的用户数据。我不知道如何使用请求的body
体的IO Bytestring
执行映射查找、检索数据并将结果以json编码发送回
我曾尝试使用fmap
通过testring
提取,然后unpack
将其转换为字符串进行查找,但无论我做什么,我最终都会跟踪与该死的IO
monad相关的类型错误
无论如何,以下是相关代码:
{-# LANGUAGE OverloadedStrings #-}
import qualified Data.ByteString as B
import qualified Data.ByteString.Char8 as B8
import qualified Data.Map as Map
import Data.Aeson
import Network.Wai
import Network.Wai.Parse
import Network.Wai.Middleware.Static
import Network.HTTP.Types
import Network.Wai.Handler.Warp (run)
userInfo :: Map.Map String (Map.Map String String)
userInfo = Map.fromList [("jsmith", Map.fromList [("firstName", "John"),
("lastName", "Smith"),
("email", "jsmith@gmail.com"),
("password", "Testing012")]),
("jeff.walker", Map.fromList [("firstName", "Jeff"),
("lastName", "Walker"),
("email", "jeff.walker@gmail.com"),
("password", "Testing012")])]
getUserInfo :: B.ByteString -> Map.Map String String
getUserInfo body =
case Map.lookup (B8.unpack body) userInfo of
(Just x) -> x
Nothing -> Map.empty
app :: Application
app request respond = do
case rawPathInfo request of
"/" -> respond index
"/api/my-data" -> respond $ myData (getUserInfo (requestBody request))
_ -> respond notFound
index :: Response
index = responseFile
status200
[("Content-Type", "text/html")]
"../client/index.html"
Nothing
myData :: IO (Map.Map String String) -> Response
myData user = responseLBS
status200
[("Content-Type", "application/json")]
(encode user)
notFound :: Response
notFound = responseLBS
status404
[("Content-Type", "text/plain")]
"404 - Not Found"
main :: IO ()
main = do
putStrLn $ "http://localhost:8080/"
run 8080 $ staticPolicy (addBase "../client/") $ app
这将导致以下错误:
src/Core/Main.hs:32:54:
Couldn't match expected type ‘B8.ByteString’
with actual type ‘IO B8.ByteString’
In the first argument of ‘getUserInfo’, namely
‘(requestBody request)’
In the first argument of ‘myData’, namely
‘(getUserInfo (requestBody request))’
我可以很容易地将getUserInfo
和myData
的类型更改为iobytestring->IO(Map.Map String)
和IO(Map.Map String)->Response
,但我最终会遇到更多的类型错误。类型让我头晕目眩。因为requestBody
有以下类型:
requestBody :: Request -> IO ByteString
结果表达式不能直接传递给getUserInfo
,它接受ByteString
您可以做的是,假设应用程序
只是请求->(响应->IO响应已接收)->IO响应已接收
,并且在应用程序
中,您处于IO
单子中,使用do
符号提取ByteString
,如下所示:
str <- requestBody request
app :: Application
app request respond = do
str <- requestBody request
case rawPathInfo request of
"/" -> respond index
"/api/my-data" -> respond $ myData (getUserInfo str)
_ -> respond notFound
此时,myData
可以简单地接受一个Map
:
myData :: Map.Map String String -> Response
不过,在深入了解WAI之前,您肯定应该阅读更多有关Monad和IO的信息。应用程序
只是请求->(响应->IO响应已接收)->IO响应已接收
。这意味着在app request respond=..
中,您可以执行IO操作,生成bytestring,然后将该bytestring传递给代码其余部分中的纯函数。将respond$myData(getUserInfo(requestBody请求))
更改为类似do的内容{x Response
requestBody
后来被弃用,取而代之的是一个更准确的名称:getRequestBodyChunk
;因为这是requestBody
一直在做的事情:返回请求体的一个块,而不是全部。因此,我认为您在这里发布的解决方案行不通。