もちっとメモ

もちっとメモ

もぐりのエンジニアが日々の中で試してみたことを気が向いたときに書き連ねていきます

それでもはてなブログを自分のホームページに埋め込みたい

2021/1/31に、CORS制限回避のために使っていた https://github.com/Rob--W/cors-anywhere が悪用が多すぎるために利用を制限したようです。 ※教えてくださった読者さんありがとうございます

github.com

この関係で、前回の方法ではRSSの取得ができなくなってしまいました。 t-n-clark.hatenadiary.jp

下記記事にも書かれている通り、本来、フロントエンドから直接外部サービスのAPIを呼ぶのは邪道であって、自前でAPIを立てるのが正攻法のようです。 medium.com career.levtech.jp

そこで、はてなブログAPIを叩くバックエンドのAPIを用意して、それをフロントエンドから呼びに行くようにすることにしました。

※ちなみにフロントエンド(React)から直接はてブAPIを呼び出そうともしてみましたが、同じくCORSエラーに遭遇しました。 そりゃそうですよね。

APIGCPAWS、Herokuなど好きな場所に立てればいいのですが、サーバの管理が不要でデプロイが簡単なGoogle Apps Script(以下、GAS)で作ることにしました。

※GASの使い方などについては、さまざまな記事で紹介されているので、ここでは割愛します。

まずは、はてブAPIを使うための準備をします。

はてブAPIは使用用途別にいろいろな種類が用意されているので、用途に合ったものを選択します。 developer.hatena.ne.jp 使用する際は、利用規約に気を付けましょう。 developer.hatena.ne.jp

今回はお試しなので、一番認証が簡単なBasic認証を選びました。 developer.hatena.ne.jp

Basic認証はDeveloper登録不要で使えます。

より強力なセキュリティ認証であるOAuth認証を使う場合はDeveloper登録が必要です。 登録方法は下記を参考にしてください。 developer.hatena.ne.jp

Basic認証APIキーはブログの管理画面から調べられます。 合わせてルートエンドポイントも確認しておきます。 http://blog.hatena.ne.jp/my/config/detail

はてブAPIの使い方がわかったので、続いて、GASではてブAPIを叩いて必要情報を返却する自前APIの実装をしていきます。

GASから取得するサンプルはこの記事が参考になります。 といってもただ単純にfetchしているだけです。 www.kotanin0.work

取得結果の細かい仕様は下記の記事が参考になります。 korosuke613.hatenablog.com

例えば、こんな感じで取ってこれます。 your_root_endpointyour_api_keyのところには先ほど管理画面で確認したルートエンドポイントとAPIキーが入ります。

function fetchHatenaFeeds() {
  const url = "your_root_endpoint/entry";
  const username = "your_username"
  const apiKey = "your_api_key"
  const options = {
    "method": "GET",
    'headers' : {'Authorization' : 'Basic ' + Utilities.base64Encode(username + ':' + apiKey)}
  }
  var xml = UrlFetchApp.fetch(url,options).getContentText();
  return xml;
}

変数名からわかるようにはてブAPIから取得できる情報はXML形式になっています。 このままだと扱いにくいので、必要な情報だけ抜き出しでJSON形式に変換してしまいましょう。

function parseXmlContent(xml){
  var contentList = [];
  var entries = xmlToJson(xml).feed.entry;
  entries.map((entry)=>{
    if(entry.control.draft.Text === "no"){
      contentList.push({
        "title": entry.title.Text,
        "pubDate": entry.published.Text,
        "link": entry.link[1].href,
      })
    }
  })
  return contentList
}

こんな感じでxmlToJson()でエントリーを変換して、所望のカラムを取り出して連想配列に格納します。 この例では、

  • title
  • pubDate
  • link

を最終的に返す仕様になっています。

xmlToJson()の中身は以下の通りです。 こちらのサンプルコードをそのまま使わせてもらいます。 gist.github.com

データ取得~返却用の連想配列に変換までの流れをまとめて1つの関数にしてしまいましょう。

function getHatenaFeeds(){
  var xml = fetchHatenaFeeds();
  var contentList = parseXmlContent(xml);
  return contentList;
}

最後にGETリクエストの受け付け関数を用意します。 GASの場合はdoGetという名前の関数がエンドポイントになります。

GASではあらかじめ登録された名前の関数を作ることで、 イベントをトリガーにスクリプトを実行できる シンプルトリガーという仕組みがあります。

今回の場合は、フロントエンドからのGETリクエストがイベントになります。

上記で作ったgetHatenaFeeds()で取得した情報をJSON形式に変換して返しています。

function doGet(e){
  var data = getHatenaFeeds();
  var payload = JSON.stringify(data);
  var output = ContentService.createTextOutput();
  output.setMimeType(ContentService.MimeType.JSON);
  output.setContent(payload);

  return output;
}

これら一連のスクリプトをデプロイして公開すれば、自分のはてブRSS情報が取得できるAPIが完成です。

あとは、前回の実装でRSSParserを使っていたところをaxiosに取り替えてやれば、OKです。

www.npmjs.com

前回

urls.map((url) => {
            rssParser.parseURL(url)
                .then((feed) => {
                    // 新たに取得したfeedを取り出す

今回

urls.map((url) => {
            axios.get(url)
                .then((feed) => {
                    // 新たに取得したfeedを取り出す

これで同じ状態に復旧できました。やった~!

※ホームページお引越ししました。 sashimimochi.netlify.app