Cloud Functions for Firebase にサイトの OGP 情報を JSON で返す エンドポイントを設置してみた

どうも、たくチャレ(@takuchalle)です。

このブログで Twitter Card みたいなリンクをつけたいと思って Hugo で JSON を取得する方法を書きました。 残りは、サイトの OGP 情報を返す JSON サーバを用意する必要があります。

そこでCloud Functions for Firebaseを使って JSON を返せるようにしてみました。しかし、理由は後述しますがHugoと相性が悪かったので最終的には使いませんでした。

でも、初めてCloud Functions for Firebaseを使ってみたし、殆ど自分で書いてないけど TypeScript も使えたので備忘録も含めて残しておきます。

Cloud Functions for Firebase のセットアップ

基本的に公式ドキュメントの通りにセットアップすればよいです。

firebase init functionsのときに TypeScript を選択してください。

=== Functions Setup

A functions directory will be created in your project with a Node.js
package pre-configured. Functions can be deployed with firebase deploy.

? What language would you like to use to write Cloud Functions?
  JavaScript
❯ TypeScript

残りはすべてデフォルトで問題ないです。

API の実装

必要なパッケージのインストールをします。package.jsonにも追記したいので--saveオプションをつけます。 Web フレームワークのexpressと HTML ファイルから OGP 情報をパースするogp-parserを使います。 expressは使わなくても実現できそうでしたが、使ってる人も多そうだったので使ってみました。

$ npm install --save ogp-parser
$ npm install --save express

実際のコードはこちらです。これをデプロイするとhttps://xxxx.cloudfunctions.net/api/ogpというエンドポイントができます。 エンドポイントに OGP 情報を取得したいサイトの URL を?url=https://xxxxxxx.comのようにクエリで渡します。 クエリで渡された URL をそのままogp-parserに渡すと OGP 情報の JSON が生成されるので、それをレスポンスとして返しています。

import * as functions from 'firebase-functions';
import * as ogpparser from 'ogp-parser';
import * as express from 'express';

const app = express()

app.get('/ogp', (req, res) => {
  if (req.query.url == undefined) {
    res.status(404).send('Sorry, we cannot find that!');
    return;
  }

  const url: string = req.query.url
  ogpparser(url, true).then(function(data) {
    res.send(data);
  }).catch(function(error) {
    res.status(404).send('Sorry, we cannot find that!');
  });
});

const api = functions.https.onRequest(app)
module.exports = { api }

Cloud Functions for Firebaseローカルで動作確認する方法があるので、それを使って動作確認・デバッグをしました。

Hugo ではうまく使えなかった理由

ogp-parsernpm サイトに JSON のサンプルが書いてありますが、それを抜粋しました。

{
    "title": "The Open Graph protocol",
    "ogp": {
        "og:title": [
            "Open Graph protocol"
        ],
        "og:url": [
            "http://ogp.me/"
        ],
    }
}

Hugoの中で$data.titleという形でタイトルを取得できるのですが、$data.ogp.og:urlのようにセミコロンがあると URL が取得できなかったのです。 もしかしたらこの場合でもアクセスする方法があるのかもしれませんが、調べてみたところ見つからなかったので諦めました。

ogp-parserでそうしているというより、ざっとコードを見た感じその中で使っているライブラリ(htmlparser2とか?)がこのような形の JSON になってるようでした。 なので簡単に修正できなさそうだったので、諦めました。

ぴよさんは golang でやっていたので、次は golang で試してみたいと思います。ただそうするとCloud Functions for FirebaseではできないのでCloud Functionsでやる必要があるのかなと思っています。

やってみた懸念点

Hugoとの相性が良くなかったのでこの方法は今回は使わなくなりました。不正にアクセスされまくると怖いのでエンドポイントも消しました。

書いていて気になったのは

  • テストってどう書くの?
  • 悪意のある人がアクセスしようとしたらどうするの?
  • アクセス制御はベーシック認証で十分なの?

あたりですかね。

参考サイト

同じカテゴリの記事