在 Yesod Handler 中创建带有查询参数的路由
Create a route with query params in Yesod Handler
我想将分页结果添加到站点地图。比方说 /blog, /blog?page=1, ...
我的路由定义如下所示:
/blog BlogR GET
页面参数是可选的。如何将 /blog?page=1 添加到站点地图。站点地图模块需要 Route App。所以我只能 link BlogR 但不知道如何使用参数创建路由。只需使用
即可轻松重定向
redirect (BlogR, [("page", 1)]) // /blog?page=1
模板也有插值。但是我不知道如何在处理程序中创建 Route App。
getPage :: Int -> Route App
getPage number = ???
非常感谢!
据我所知,如果不做大量工作,您无法用该签名真正定义 getPage
。假设您正在使用 mkYesod
生成样板文件,它已经生成了一个 Route App
数据类型(和关联的 renderRoutes
函数),没有提供查询参数的规定。
您最好的选择可能是从使用查询参数切换到对 Yesod 更友好的 URL,例如 /blog/page/1
。更好的是,不要使用基于页面的系统,而是将您的 URL 建立在博客 post 的 ID 号上以启动该页面,以便 /blog/start/15
显示您的博客以 [=34] 开头=]ing number 15。如果你走这条路(双关语意),你会自动得到一个永久的 URL(这样 /blog/start/15
总是从同一个博客条目开始),你可以安排这样你就可以 "usually" 分页到可预测的起始编号以方便缓存等等。
但是,如果您真的想欺骗 yesod-sitemap
生成带有查询参数的路由,以下独立示例可能会有所帮助。这里,getSitemapR
是 Yesod.Sitemap.sitemapList
的重新实现,它使用 getUrlRenderParams
代替 getUrlRender
,允许处理查询参数。
我对管道一无所知,所以我不知道我对 getSitemapR
的实现是否特别聪明——我只是从 yesod-sitemap
复制并修改代码直到它输入-已检查。
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
import Yesod
import Yesod.Sitemap
import Data.Text (Text)
-- stuff needed for getSitemapR
import Text.XML.Stream.Render (renderBuilder)
import Data.Conduit (($=), yield, Flush(..))
import qualified Data.Conduit.List as CL
import Data.Default (def)
data Blog = Blog
mkYesod "Blog" [parseRoutes|
/blog BlogR GET
/sitemap SitemapR GET
|]
instance Yesod Blog
getBlogR :: Handler Html
getBlogR = do
page <- lookup "page" . reqGetParams <$> getRequest
defaultLayout $ case page of
Nothing -> [whamlet|<p>Top of blog|]
Just n -> [whamlet|<p>Page #{n} of blog|]
-- |Sitemap route is app route plus query parameters
data SMRoute = SMRoute (Route Blog) [(Text, Text)]
sitemapRoutes :: [SitemapUrl SMRoute]
sitemapRoutes = map (\u -> SitemapUrl u Nothing Nothing Nothing)
[ SMRoute BlogR []
, SMRoute BlogR [("page", "1")]
, SMRoute BlogR [("page", "2")]
, SMRoute BlogR [("page", "3")]
]
getSitemapR :: Handler TypedContent
getSitemapR = do
let urls = mapM_ yield sitemapRoutes
renderParams <- getUrlRenderParams
let render (SMRoute r qs) = renderParams r qs
respondSource typeXml $ do
yield Flush
urls $= sitemapConduit render $= renderBuilder def $= CL.map Chunk
main :: IO ()
main = warp 3000 Blog
我想将分页结果添加到站点地图。比方说 /blog, /blog?page=1, ...
我的路由定义如下所示:
/blog BlogR GET
页面参数是可选的。如何将 /blog?page=1 添加到站点地图。站点地图模块需要 Route App。所以我只能 link BlogR 但不知道如何使用参数创建路由。只需使用
即可轻松重定向redirect (BlogR, [("page", 1)]) // /blog?page=1
模板也有插值。但是我不知道如何在处理程序中创建 Route App。
getPage :: Int -> Route App
getPage number = ???
非常感谢!
据我所知,如果不做大量工作,您无法用该签名真正定义 getPage
。假设您正在使用 mkYesod
生成样板文件,它已经生成了一个 Route App
数据类型(和关联的 renderRoutes
函数),没有提供查询参数的规定。
您最好的选择可能是从使用查询参数切换到对 Yesod 更友好的 URL,例如 /blog/page/1
。更好的是,不要使用基于页面的系统,而是将您的 URL 建立在博客 post 的 ID 号上以启动该页面,以便 /blog/start/15
显示您的博客以 [=34] 开头=]ing number 15。如果你走这条路(双关语意),你会自动得到一个永久的 URL(这样 /blog/start/15
总是从同一个博客条目开始),你可以安排这样你就可以 "usually" 分页到可预测的起始编号以方便缓存等等。
但是,如果您真的想欺骗 yesod-sitemap
生成带有查询参数的路由,以下独立示例可能会有所帮助。这里,getSitemapR
是 Yesod.Sitemap.sitemapList
的重新实现,它使用 getUrlRenderParams
代替 getUrlRender
,允许处理查询参数。
我对管道一无所知,所以我不知道我对 getSitemapR
的实现是否特别聪明——我只是从 yesod-sitemap
复制并修改代码直到它输入-已检查。
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
import Yesod
import Yesod.Sitemap
import Data.Text (Text)
-- stuff needed for getSitemapR
import Text.XML.Stream.Render (renderBuilder)
import Data.Conduit (($=), yield, Flush(..))
import qualified Data.Conduit.List as CL
import Data.Default (def)
data Blog = Blog
mkYesod "Blog" [parseRoutes|
/blog BlogR GET
/sitemap SitemapR GET
|]
instance Yesod Blog
getBlogR :: Handler Html
getBlogR = do
page <- lookup "page" . reqGetParams <$> getRequest
defaultLayout $ case page of
Nothing -> [whamlet|<p>Top of blog|]
Just n -> [whamlet|<p>Page #{n} of blog|]
-- |Sitemap route is app route plus query parameters
data SMRoute = SMRoute (Route Blog) [(Text, Text)]
sitemapRoutes :: [SitemapUrl SMRoute]
sitemapRoutes = map (\u -> SitemapUrl u Nothing Nothing Nothing)
[ SMRoute BlogR []
, SMRoute BlogR [("page", "1")]
, SMRoute BlogR [("page", "2")]
, SMRoute BlogR [("page", "3")]
]
getSitemapR :: Handler TypedContent
getSitemapR = do
let urls = mapM_ yield sitemapRoutes
renderParams <- getUrlRenderParams
let render (SMRoute r qs) = renderParams r qs
respondSource typeXml $ do
yield Flush
urls $= sitemapConduit render $= renderBuilder def $= CL.map Chunk
main :: IO ()
main = warp 3000 Blog