Pre-renderingでビルド時に外部APIからデータを取得したい {Jamstack => Next.js}

2022.02.01

以前構築していた動画視聴用のアプリ

をJamstackなアーキテクチャに作り直そうとふと思い、Next.jsにチャレンジ中の覚書きです

Jamstackの基本原則にpre-renderingというものがあります。 これは、

必要なときに事前にビューを表すマークアップを生成します。これはオンデマンドではなくビルド中に発生するため、Webサーバーは受信したリクエストごとにこのアクティビティを実行する必要はありません。

ということです。 サーバー側は事前に作成されたHTMLをクライアント側に返すだけなので、パフォーマンスは高くなるよということですね。

Jamstackのサイトにも静的ファイルを生成するフレームワークがたくさん載っていました。

今回変更しようと思った箇所が、クラウド上に保存されている動画のメタデータ(検索用)から一覧を取得するAPIの実行です。

以前はクライアントサイドのjavascriptからAPI Gatewayを叩いていましたが、これをNext.jsのgetStaticProps(※1)を使ってビルド時に取得してしまいます( CSR(Client Side Rendering) から SSG(Static Site Generation) に )

※1 getStaticProps

そんなに更新されない、最新のデータを件数固定で取得する という仕様なので、SSGでもいいだろうと思った次第です。

getStaticPropsは、Next.jsのPageからのみエクスポートできます。 componentから呼び出してエラーしてハマっていました。ちゃんとドキュメント読まないとダメですね。。。

以下のようにエクスポートし、返却してあげれば使えます。

export async function getStaticProps(context) {
  return {
    props: {}, // will be passed to the page component as props
  }
}

getStaticPropsがサーバー側だけで実行され、クライアント(ブラウザ)では実行されません。

ビルド時にデータベースやAPIにアクセスして取得したデータをHTMLとjsonファイルに生成するので、 アクセスごとにデータが変わることはないので注意が必要です。

リアルタイム性がそんなには必要ないけどパフォーマンスは高くしたい という今回のケースではぴったりのソリューションでした。

以下がgetStaticPropsで外部APIから一覧データを取得するサンプルコード。

const HomePage = ( {movies} ) => {
  return (
    <main>
      <Header />
      <Container>
            <h4>Recommended for You</h4>

            <Content>
                {movies.data.map((movie) => (
                    <Wrap key={movie.contents_id}>
                        <Link href={`/detail/${movie.contents_id}`}>
                            <a><img src={movie.thumbnail_url} alt={`${movie.title}のサムネイル`} /></a>
                        </Link>
                    </Wrap>
                ))}
            </Content>
        </Container>
    </main>
   )
}

export async function getStaticProps() {
   // API実行のために必要なトークンを取得¥
  const token = await getContentsApiAccessToken()

  // 外部APIのデータをフェッチ
  const response = await fetch(<<APIのURL>>, {
      headers: {
          Authorization: `Bearer ${token}`,
          'Content-Type': 'application/json',
          'X-Requested-With': 'XMLHttpRequest'
      },
  });

  const movies = await response.json();

  return {
      props: {
          movies,
      },
    }
}

export default HomePage

作成しているアプリケーションをJamstackなアーキテクチャに変更していく際、 一覧のデータはPre-renderingで対応できる とわかりましたが、 動画の個別ページやリクエストごとに変更したい内容(コンテンツの検索とかスターの数とか)はどうするの? といったことが次の課題です。