🗂

動的にOGPを更新する

2022/07/05に公開

なぜOGPを更新したいか

twitterでスポーツの試合速報botを運用しており、試合経過とともにOGPを変化させたいと思いました。

OGP(Open Graph Protocol)とは

Facebook、TwitterなどのSNS上でシェアされた時やシェアされたい時に、ページのタイトル、URL、概要、画像(サムネイル)を正しく伝えるためにHTMLソースに記述するタグ情報です。

現行の仕様

野球の試合速報なのですが、twitterでシェアしていたのは試合詳細で、
現在どのような進行になっているかの情報を持っているページではありませんでした。
https://cap-scorebook.com/game/fefc5f38-3101-4675-8baa-fdc59cc589bd

また、固定のページのOGPを変更するには、
https://cards-dev.twitter.com/validator
でキャッシュをクリアしなければならないという課題もあります。

試行錯誤①

まず、試合の経過がわかるページ(打席詳細)があるのですが、そこをシェアするようにしようとしました。
https://cap-scorebook.com/game/fefc5f38-3101-4675-8baa-fdc59cc589bd/1/3/4

ただ、このページでは計算ロジックとデータフェッチが密結合になっており、NextJSのSSRが使えないという致命的な問題がありました。

試行錯誤②

試合進行を入力すると、vercel functionsに情報を送ってツイートするという形を取っているので、その時点の試合状況を全て持っています。
ユーザにシェアするページを変えずに状況だけ変える、となるとクエリで渡せばいいのでは...というところにたどり着きました。
ページに渡したクエリを全てOGPに渡せば動的にOGPを生成できるということです。

https://cap-scorebook.com/game/fefc5f38-3101-4675-8baa-fdc59cc589bd?firstTeamName=三田%2F相模原工科大&lastTeamName=早大世田谷&first_run=7&last_run=3&inning=3&isTop=1&is1st=0&is2nd=0&is3rd=0&out=1

文字数制限もあるので投手、打者、結果はOGPからオミットしました。

SSR時にクエリからmetaタグを組み立てる

export const getServerSideProps = async ({ params, query }) => {
  const response = await fetch(CAP_BACKEND + "/game/" + params.game_id);
  const { first_team, last_team, first_run, last_run,inning,  out,isTop, is1st, is2nd, is3rd, pitcher, batter, result } = query;
  if (response.status === 200) {
    const game = await response.json();
    return {
      props: {
        game,
        ctx:{
          first_team: first_team ? first_team : game.first_team_name,
          last_team: last_team ? last_team: game.last_team_name,
          first_run: !isNaN(Number(first_run)) ? first_run :game.first_run,
          last_run : !isNaN(Number(last_run)) ? last_run: game.last_run,
          inning : inning ? inning :null,
          out: !isNaN(Number(out)) ? out :null,
          is1st: Number(is1st),
          is2nd: Number(is2nd),
          is3rd: Number(is3rd),
          batter: batter ?? null,
          pitcher : pitcher ?? null,
          result : result ?? null,
          isTop: isTop ?? null
        }
      },
    };
  } else {
    return {
      props: {},
    };
  }
};

このときに取れるクエリはpathParamとqueryParamが混ざっているのでそこだけ要注意です。
OGPはvercel functionsとnode-canvasを使用しています。

Discussion