Haskell Servant从处理程序获取当前路由/URL
我想获取与我的处理程序对应的当前路径。以下是我的服务器模型,仅供参考:Haskell Servant从处理程序获取当前路由/URL,haskell,request,servant,Haskell,Request,Servant,我想获取与我的处理程序对应的当前路径。以下是我的服务器模型,仅供参考: type ServerAPI = "route01" :> Get '[HTML] Text :<|> "route02" :> "subroute" :> Get '[HTML] Text :<|> "route03" :> Get '[HTML] Text [编辑]我刚刚注意到我正在查看旧版本servant的api,这不再有效。新的r
type ServerAPI =
"route01" :> Get '[HTML] Text
:<|> "route02" :> "subroute" :> Get '[HTML] Text
:<|> "route03" :> Get '[HTML] Text
[编辑]我刚刚注意到我正在查看旧版本servant的api,这不再有效。新的
route
具有类型签名route::Proxy-api->Context-Context->Delayed-env(Server-api)->Router-env
,我真的看不到从这里获取请求的方法
而不是将route1和2handler
类型签名设置为Request->Handler Text
,但我在尝试创建HasServer
实例时遇到此错误:
`Server' is not a (visible) associated type of class `HasServer'
最后,我要指出的是,我的最终目标是从处理程序中获取当前路由,在数据库中为路由添加访问计数只是为了举例。我不想用更好的方法来计算访问次数或类似的事情。
我不知道如何自动完成,但可以使用该功能“手动”完成
这个想法是,如果你有一个API
type ServerAPI =
"route01" :> Get '[HTML] Text
:<|> "route02" :> "subroute" :> Get '[HTML] Text
:<|> Route3
type Route3 = "route03" :> Get '[HTML] Text
如果路由具有参数,则还必须传递处理程序获取的参数。例如:
type ServerAPI =
...
:<|> Route4
type Route4 = "route04" :> Capture "cap" Int :> Get '[JSON] Text
type ServerAPI =
"route01" :> Get '[JSON] Text
:<|> "route02" :> "subroute" :> Get '[JSON] Text
:<|> "route03" :> Get '[JSON] Text
route1and2Handler :: String -> Handler Text
route1and2Handler route = do
-- addVisitCountForRouteToDatabaseOrSomethingOfThatSort...
return (pack route)
route3Handler :: Handler Text
route3Handler = return "Hello, I'm route 03"
server :: Server ServerAPI
server = route1and2Handler "route01" :<|> route1and2Handler "route02" :<|> route3Handler
您必须对每个路由执行此操作。当您向处理程序添加“路由”参数时,您可以在组合服务器的处理程序时通过函数应用程序设置参数值
根据您的示例:
type ServerAPI =
...
:<|> Route4
type Route4 = "route04" :> Capture "cap" Int :> Get '[JSON] Text
type ServerAPI =
"route01" :> Get '[JSON] Text
:<|> "route02" :> "subroute" :> Get '[JSON] Text
:<|> "route03" :> Get '[JSON] Text
route1and2Handler :: String -> Handler Text
route1and2Handler route = do
-- addVisitCountForRouteToDatabaseOrSomethingOfThatSort...
return (pack route)
route3Handler :: Handler Text
route3Handler = return "Hello, I'm route 03"
server :: Server ServerAPI
server = route1and2Handler "route01" :<|> route1and2Handler "route02" :<|> route3Handler
其中有两个问题:
如何获取当前请求或URL
如何获得当前的“路线”
请注意,URL(例如/route12/42
)与路由不同
(例如,`route12:>Capture“id”Int:>Get'[JSON]Int)。
让我们看看如何解决这两个问题
简短语言pragma和导入部分
{-#语言约束种类}
{-#语言数据类型}
{-#派生通用语言}
{-#语言灵活语境#-}
{-#语言灵活实例}
{-#语言MultiParamTypeClasses}
{-#语言重载字符串}
{-#语言等级}
{-#语言范围类型变量#-}
{-#语言类型族{-}
{-#语言类型运算符{-}
{-#语言不可判定实例}
{-#语言不可判定超类}
{-#选项{GHC-Wno孤儿}
模块主要在哪里
导入数据。可能(来自可能)
导入控制.Monad.IO.Class(liftIO)
导入System.Environment(getArgs)
进口GHC.仿制药(到,从,M1(..),K1(..,(:*:)(..)
--用于“不安全”vault密钥创建
导入System.IO.Unsafe(unsafePerformIO)
将符合条件的Data.ByteString.Char8导入为BS8
将限定的Data.Vault.Lazy导入为V
导入合格网络。Wai为Wai
导入合格的Network.Wai.Handler.Warp作为Warp
进口佣人
导入Servant.API.Generic
导入Servant.Server.Generic
导入Servant.Server.Internal.RoutingApplication(passToServer)
如何获取当前的请求
对象或URL
将当前的WAI
请求
传递给处理程序实际上相当简单。
这是“懒惰”的方法,我们在请求中要求“一切”,
我们必须小心处理程序(例如,我们不能触摸requestBody
)。
这个“组合器”还将实现与wai
服务器实现联系起来,
这是一个实现细节
(除了Raw
之外,servant服务器中没有任何其他内容公开wai
内部结构)
其思想是使服务器(Wai.Request:>api)=Wai.Request->Server-api
。
如果我们想象一下,我们有这样的功能,
我们可以使用Servant.API.Generic
(参见“使用泛型”食谱)编写:
数据路由1路由=路由1
{route11::route:-Wai.Request:>“route1”:>获取'[JSON]Int
,route12::route:-Wai.Request:>route2:>Capture“id”Int:>Get'[JSON]Int
}
派生(通用)
路由1::路由1服务器
路由1=路由1
{route11=\req->liftIO$do
设p=Wai.rawPathInfo请求
BS8.putStrLn p
返回(BS8.p)
,route12=\req i->liftIO$do
设p=Wai.rawPathInfo请求
BS8.putStrLn p
返回(成功i)
}
app1::应用程序
app1=通用服务路由1
我们定义一个Routes1
数据类型,实现routes1asserver
值并将其转换为
进入wai
的应用程序
。然而,要编译这个示例,我们需要一个
附加实例。我们在
路由的实现
instance HasServer api ctx=>HasServer(Wai.Request:>api)ctx其中
键入ServerT(Wai.Request:>api)m=Wai.Request->servertapi m
带上下文的提升服务器\uPC nt s=
提升服务器WithContext(代理::代理api)pc nt。s
路由u-ctx d=路由(代理::代理api)ctx$
passToServer d id
这个解决方案是一个很好的快速修复方案,但可以说还有更好的方法
特定组合子
我们可能会注意到,我们的两个处理程序都使用Wai.rawPathInto-req
调用。
这应该提醒我们。特定的组合器更优雅。
能够在核心框架之外创建新的组合器,
是仆人
的设计原则之一
数据RawPathInfo
实例HasServer api ctx=>HasServer(RawPathInfo:>api)ctx,其中
键入ServerT(RawPathInfo:>api)m=BS8.ByteString->servertapi m
带上下文的提升服务器\uPC nt s=
提升服务器WithContext(代理::代理api)pc nt。s
路由u-ctx d=路由(代理::代理api)ctx$
passToServer d Wai.rawPathInfo
使用新的RawPathInfo
combinator,我们可以重新实现我们的应用程序:
数据路由2路由=路由2
{route21::rout
type ServerAPI =
...
:<|> Route4
type Route4 = "route04" :> Capture "cap" Int :> Get '[JSON] Text
ghci> :set -XKindSignatures -XDataKinds -XTypeOperators -XTypeFamilies
ghci> :type safeLink (Proxy::Proxy ServerAPI) (Proxy::Proxy Route4)
Int -> URI
type ServerAPI =
"route01" :> Get '[JSON] Text
:<|> "route02" :> "subroute" :> Get '[JSON] Text
:<|> "route03" :> Get '[JSON] Text
route1and2Handler :: String -> Handler Text
route1and2Handler route = do
-- addVisitCountForRouteToDatabaseOrSomethingOfThatSort...
return (pack route)
route3Handler :: Handler Text
route3Handler = return "Hello, I'm route 03"
server :: Server ServerAPI
server = route1and2Handler "route01" :<|> route1and2Handler "route02" :<|> route3Handler
import Network.Wai.Middleware.RequestLogger (logStdoutDev)
...
app :: Application
app = serve serverAPI server
main :: IO ()
main = run 8081 $ logStdoutDev app