【Next.js × microCMS】人気記事一覧を表示してみた
フロントエンドおはこんにちばんは。今回は Next.js × microCMS で 人気記事一覧を Google Analytics Reporting API v4 を利用し表示してみました!
よくブログとかで人気記事一覧とか目にしますよね。WordPress の場合はプラグインを利用すれば比較的簡単に出来そうですが、自作ブログだとどうすべきか悩みました。
そこで今回は、Google Analytics Reporting API v4  を利用して人気記事一覧を表示する方法を紹介していきます。
実行環境
- Next.js 10.0.4
 - React 17.0.0
 
Google APIs を有効にする
プロジェクトを作成
Google APIs にアクセスし、プロジェクトの選択 をクリックし、新しいプロジェクト をクリックします。
プロジェクト名に任意の名前をつけてプロジェクトを作成します。
Google Analytics API の有効化
APIとサービスの有効化 をクリックして Google Analytics API を有効化します。


これで有効化されました。続いて認証情報を作成します。
認証情報の作成
認証情報を作成 をクリックします。
下記の情報を選択します。必要な認証情報 をクリックします。
- 使用するAPI:Analytics Reporting API
 - APIを呼び出す場所:ウェブサーバー(node.js, Tomcat など)
 - アクセスするデータの種類:アプリケーションデータ
 

下記の情報を選択します。次へ をクリックします。
- サービスアカウント名:任意
 - ロール:閲覧者
 - キータイプ:JSON
 

自動的にjsonがダウンロードされます。このjsonは後ほど利用するので、適切に保管しておきます。
Google Analytics の閲覧権限を付与
Google Analyticsの設定を行っていきます。
Google Analytics を開き、左下の歯車マーク から ビューの設定 をクリックします。
ビューIDを後ほど利用するのでメモっておいてください。
次にユーザ管理をクリックし、+ ボタンを押してユーザを追加します。
ユーザのメールアドレスには、先程ダウンロードしたjsonファイルに記載されている client_email の値を入れて、ユーザを追加します。
これでgoogle APIs周りの設定は完了です。
パッケージの追加
それでは実装を進めていきます。今回は、Node.js用のライブラリである google-api-nodejs-client を利用します。
$ yarn add googleapisページビュー上位を取得する処理
人気記事一覧を表示したいので、ページビューが上位の3位のパスを取得するコートを書いていきます。
import { analyticsreporting_v4, google } from 'googleapis';
import { isEmpty } from 'lodash';
const getTopArticle = async (): Promise<analyticsreporting_v4.Schema$GetReportsResponse> => {
  const client = await google.auth.getClient({
    scopes: 'https://www.googleapis.com/auth/analytics.readonly',
    credentials: {
      client_email: process.env.GOOGLE_APPLICATION_CLIENT_EMAIL,
      private_key: (process.env.GOOGLE_APPLICATION_PRIVATE_KEY ?? '').replace(
        /\\n/gm,
        '\n',
      ),
    },
  });
  const analyticsreporting = google.analyticsreporting({
    version: 'v4',
    auth: client,
  });
  const res = await analyticsreporting.reports.batchGet({
    requestBody: {
      reportRequests: [
        {
          viewId:  process.env.GOOGLE_ANALYTICS_VIEW_ID,
          dateRanges: [
            {
              startDate: '30daysAgo',
              endDate: '1daysAgo',
            },
          ],
          dimensions: [
            {
              name: 'ga:pagePath',
            },
          ],
          metrics: [
            {
              expression: 'ga:pageviews',
            },
          ],
          orderBys: [
            {
              fieldName: 'ga:pageviews',
              sortOrder: 'DESCENDING',
            },
          ],
          pageSize: 3,
          dimensionFilterClauses: [
            {
              filters: [
                {
                  dimensionName: 'ga:pagePath',
                  operator: 'REGEXP',
                  expressions: ['^/blogs/[0-9a-zA-Z\\-]+$'],
                },
              ],
            },
          ],
        },
      ],
    },
  });
  return res.data;
};
const getTopArticlePaths = async (): Promise<string[]> => {
  const topArticle = await getTopArticle();
  const ids: string[] = [];
  const rows = topArticle.reports
    ? topArticle.reports[0]?.data?.rows ?? []
    : [];
  rows.forEach((row) => {
    if (row.dimensions && !isEmpty(row.dimensions)) {
      ids.push(row.dimensions[0].replace('/blogs/', ''));
    }
  });
  return ids;
};
export { getTopArticle, getTopArticlePaths };
以下の環境変数は先ほどダウンロードしたjsonの clientemail と privatekey を利用します。view_id は先ほどメモしたやつです。
process.env.GOOGLE_APPLICATION_CLIENT_EMAIL
process.env.GOOGLE_APPLICATION_PRIVATE_KEY
process.env.GOOGLE_ANALYTICS_VIEW_ID
ブログのページビューのみを取得したいので、正規表現で /blogs/英数字ハイフン が含むのみを取得するようにしています。
dimensionFilterClauses: [
{
  filters: [
    {
      dimensionName: 'ga:pagePath',
      operator: 'REGEXP',
      expressions: ['^/blogs/[0-9a-zA-Z\\-]+$'],
    },
  ],
}]
次に以下のようにページビュー上位3位までの記事を取得します。
export const getStaticProps: GetStaticProps = async (): Promise<{
  props: Props;
}> => {
  const ids = await getTopArticlePaths();
  const str = ids.join(',');
  const key = {
    headers: { 'X-API-KEY': process.env.API_KEY ?? '' },
  };
  const topBlogs = await fetch(
    `https://your-service.microcms.io/api/v1/blogs?ids=${str}`,
    key,
  )
    .then((res) => res.json())
    .catch(() => null);
  const topArticleBlogs = compact(
    ids.map((id) => topBlogs?.contents.find((b) => b.id === id)),
  );
  return {
    props: {
      topArticleBlogs,
    },
  };
};
以下は microCMS が順番を作成順に変えてしまうので、Articleのid順に並び替えています。
const topArticleBlogs = compact(
    ids.map((id) => topBlogs?.contents.find((b) => b.id === id)),
);
これで人気記事を取得出来たはずなので、あとは良しなに表記するだけです。お疲れ様でした。
さいごに
今回は人気記事一覧を表示する方法についてご紹介しました!意外と調べても参考になる実装方法がなかったので誰かの参考になれば幸いです。
(microCMSのidsはidの順番に返して欲しいと思うこの頃。方法あるのかな?)