このブログに RSS を付けました。

このブログは Haskell の Web フレームワークである Yesod 上で動かしています。 それ自体の話は今後書くとして、今回は RSS の設置について書きます。

Yesod 上で設置できる RSS は yesod-newsfeed というのがあるようです。

yesod-newsfeed は Atom と RSS のどちらも対応しています。 Atom だけ配信するなら Yesod.AtomFeed を、RSS だけ配信するなら Yesod.RssFeed を、両方配信するなら Yesod.Feed を使います。

フィードを配信するのは簡単です。Feed 型のデータを作って、それをそれぞれの方法で配信するだけです。

import qualified Yesod                                  as Y
import qualified Yesod.Feed                             as YFeed

import Foundatin (Route, App)

data Blog = ... -- 適当なブログの定義があるとする

recentBlogs :: [Blog]
recentBlogs = undefined -- 最新のブログ何件か取得する

toFeed :: [Blog] -> IO (YFeed.Feed (Route App))
toFeed blogs = undefined -- 適当に Feed を作る

getFeedR :: Handler Y.TypedContent
getFeedR = do
    feed <- Y.liftIO $ toFeed recentBlogs
    YFeed.newsFeed feed -- Atom と RSS の両方に対応した Feed を返す

newsFeed は、Accept ヘッダーを見て、application/atom+xml なら Atom のフィードを、application/rss+xml なら RSS のフィードを返します。

実際のところ、一番面倒なのは Feed を作る部分です。 これは以下のようになっています。

blogToHtml :: Blog -> Y.Html
blogToHtml = undefined

toEntry :: Blog -> IO (YFeed.FeedEntry (Route App))
toEntry blog = do
    html <- blogToHtml blog
    return YFeed.FeedEntry
        { YFeed.feedEntryLink    = UrlR $ blogURL blog
        , YFeed.feedEntryUpdated = blogDateTime blog
        , YFeed.feedEntryTitle   = blogTitle blog
        , YFeed.feedEntryContent = html
        }

toFeed :: [Blog] -> IO (YFeed.Feed (Route App))
toFeed blogs = do
    entries <- mapM toEntry blogs
    return YFeed.Feed
        { YFeed.feedAuthor      = "melpon"
        , YFeed.feedTitle       = "Blog :: Licensed by Meatware"
        , YFeed.feedDescription = "blog by melpon"
        , YFeed.feedLanguage    = "ja"
        , YFeed.feedLinkSelf    = FeedR
        , YFeed.feedLinkHome    = RootR
        , YFeed.feedUpdated     = YFeed.feedEntryUpdated $ head entries
        , YFeed.feedEntries     = entries
        }

結構埋める項目があって面倒です。 ただ、結構当たり前のデータを入れてるだけなので、難しい訳ではないと思います。

これでフィードを配信できるようになったので、あとはブログページに RSS を用意するだけです。

hamlet ファイルに直接書いてもいいですが、ここは Haskell のコードで書きましょう。

Y.toWidgetHead [hamlet|<link rel="alternate" type="application/rss+xml" title="RSS 2.0" href=@{FeedR}>|]

これを Blog ページへのリクエストを処理するハンドラに書けば完成です。 読者がこの Blog ページをフィードリーダーに登録すれば、フィードリーダーが RSS を見つけてくれます。