YQLを利用してRSSを取得する
はてブのホットエントリーをJSON形式で取得してReduxを利用したクライアントで表示してみます。
完成品
(左に寄っちゃってますが...)
YQL (Yahoo! Query Console)
CORSによるクロスドメイン制限があるため、Ajaxで直接RSSを取得することはできません。
PHP等のサーバーサイドでRSSを取得してクライアントに表示する必要があります。
今回はサーバーの実装をしないので、YQLを利用します。
こんな感じでSQLのようにクエリを実行すると結果が返ってきます。
最下部にあるTHE REST QUERYをcurlで叩いてみると、RSSがJSON形式で取得できます。
$ curl -X GET "https://query.yahooapis.com/v1/public/yql?q=SELECT%20*%20FROM%20rss%20WHERE%20url%20%3D%20'http%3A%2F%2Fb.hatena.ne.jp%2Fhotentry.rss'&format=json&diagnostics=true&callback=" {"query":{"count":30,"created":"2016-08-02T01:23:13Z","lang":"en-US","diagnostics":{"publiclyCallable":"true","url":{"execution-start-time":"1","execution-stop-time":"452","execution-time":"451","content":"http://b.hatena.ne.jp/hotentry.rss"},"user-time":"454","service-time":"451","build-version":"0.2.39"},"results":{"item":[{"about":"http://www.okinawatimes.co.jp/articles/-/55298","title":"スク水揚げ 奥武島で今年も大漁 | 沖縄タイムス+プラス ニュース","link":"http://www.okinawatimes.co.jp/articles/-/55298","description":"【南城】南城市の奥武島でスク漁が始まり、島の海人が ...
Fetch API
RSSを取得するだけなのでsuperagent等のモジュールではなくFetch APIを利用してみます。
redux-actions、redux-promiseと組み合わせる
fetch()はPromiseを返すのでredux-promiseにそのまま渡します。
then()でreturnした結果がreducerのnextのaction.payloadに渡されます。
// api/bookmarks.js import querystring from 'querystring' import { getRssUrl } from '../constants/ApiCategory' const YQL_URL = "https://query.yahooapis.com/v1/public/yql" const defaultParams = { format: 'json', diagnotistics: true } export default { fetchBookmarks: (category) => { const sql = `SELECT * FROM rss WHERE url = '${getRssUrl(category)}'` const data = Object.assign({}, defaultParams, { q: sql }) const url = `${YQL_URL}?${querystring.stringify(data)}` // Promiseを返す return fetch(url) .then((res) => { return res.json() }) .catch((err) => { console.log(err) }) } }
// actions/api.js import { createAction } from 'redux-actions' import * as types from '../constants/ApiActions' import api from '../api/bookmarks' export const fetchBookmarks = createAction(types.FETCH_BOOKMARKS, api.fetchBookmarks)
// reducers/bookmarks.js const bookmarks = handleActions({ [types.FETCH_BOOKMARKS]: { next: (state, action) => { let items = action.payload.query.results.item return items.map(b => bookmark(b, action)) }, throw: (state, action) => { return [] } } }, [])
今回は1つのstateを全タブで共有しているためクリック毎にrequestが飛んでしまいますが、
カテゴリ(タブ)ごとにstate持たせて管理するとrequest回数も減らせてサクサク動きますかね。