コンテンツの更新時にNext.js (App Router) でOn-demand Revalidationを実行する

最終更新日:

Table of contents

Next.js (App Router) ではデータのキャッシュを無効化する revalidation機能 として、時間単位で自動的に無効化する「Time-based Revalidation」と、手動で無効化する「On-demand Revalidation」の2種類が用意されています。
ここでは On-demand Revalidation と、Newtの Webhook を利用することで、コンテンツ情報の更新をトリガーに、該当のページのみ、キャッシュを無効化する方法を紹介します。

記事内で使用している主なソフトウェアのバージョン

  • Next.js(next): 13.5.1

前提条件

  1. Next.jsのApp Routerを利用していること
  2. Next.jsの v13.5.1 以上を利用していること(以前のバージョンでもOn-demand Revalidationは可能ですが、ファイル単位での指定となり、URL単位での指定ができません)
  3. Next.jsの Route Handlers について理解していること

概要

以下の流れで処理を行うものとします。

  1. コンテンツの更新
  2. Webhookでリクエストを送信(更新するページを特定する情報を含める)
  3. Next.jsに実装したrevalidate用のAPIが呼び出され、Webhookのbodyからどのページを更新するべきか読み取る
  4. 該当ページのキャッシュを無効化する

1. 実装前の準備

実装を始める前に、以下のことを決めましょう。

  • コンテンツの更新時に、どのページを更新するか
  • 更新するページのパスを取得するために、コンテンツのどのフィールドの情報が必要か
  • リクエストが有効なものかどうやって検証するか(そもそも検証は必要か)

ここでは以下の想定で進めます。

  • ある記事が更新された場合に、記事の詳細ページ /articles/${slug} を更新する
  • slugの情報は、各コンテンツのslugというフィールドに設定されている
  • リクエストが有効か、クエリパラメータのsecretの値で検証する

2. Revalidation処理を実装する

Next.jsの Route HandlersrevalidatePath を利用して、Revalidation処理を実装します。
この処理では、以下のことを行います。

  • リクエストが有効なものか、クエリパラメータのsecretの値で検証する(MY_SECRET_TOKEN という環境変数を利用する)
  • Webhookのbodyからslugの値を取り出す
  • /articles/${slug} のページを更新する
app/api/revalidate/route.ts
1import { revalidatePath } from 'next/cache'
2import { NextRequest, NextResponse } from 'next/server'
3
4export async function POST(request: NextRequest) {
5  const secret = request.nextUrl.searchParams.get('secret')
6  if (secret !== process.env.MY_SECRET_TOKEN) {
7    return NextResponse.json({ message: 'Invalid secret' }, { status: 401 })
8  }
9
10  const { slug } = await request.json()
11  revalidatePath(`/articles/${slug}`)
12
13  return NextResponse.json({ revalidated: true, now: Date.now() })
14}

3. 環境変数を登録する

2でリクエストの検証を行うために、MY_SECRET_TOKEN という環境変数を利用しました。
Vercelを利用する場合、Settings > Environment Variables のページから環境変数を登録できます。Vercelでの環境変数の登録について、詳細はVercelの Environment Variables のドキュメントをご確認ください。

vercel_env_vars.jpg

4. Webhookを作成する

次にWebhookを作成し、2で作成したRevalidation処理を呼び出せるようにします。
1で決めた内容をもとに、このWebhookは以下の要件を満たすように作成します。

  • URLには、Revalidation処理を呼び出すURLを指定する
  • クエリパラメータにsecretの値を設定し、3で登録した値と一致させる
  • slug情報を持たせる

Newtの管理画面に入り、スペース設定 > Webhook のページから「作成」を押します。

4-1. URLの指定

クエリパラメータにsecretの値を含め、また2で作成したRevalidation処理を呼び出すために、以下のようなURLを指定します。

https://<your-site.com>/api/revalidate?secret=<token>

例えば、ドメインが「revalidate-sample-aaa-bbb.vercel.app」で、secretが「hogehoge」の場合、https://revalidate-sample-aaa-bbb.vercel.app/api/revalidate?secret=hogehoge となります。

ScreenShot2022-07-21at11.22.36.png

4-2. ペイロードの設定

ペイロードにはslugの情報を持たせる必要があります。
以下のように {"slug": "{ content.slug }"} と指定します。

ペイロードには変更後のコンテンツ情報を持たせることができます。コンテンツ情報全体を指定することも、今回のように特定のフィールドに絞ることも可能です。

ScreenShot2022-07-21at10.56.57.png

4-3. その他の設定

最後にステータスを「有効」にして、Webhookを作成します。
ヘッダーの設定は不要です。

5. 処理を確認する

最後に、コンテンツを更新した時、該当ページのキャッシュが無効化されることを確認しましょう。

revalidatePath は実行したタイミングでキャッシュを無効化するのではなく、次に訪問されたタイミングでキャッシュを無効化することに注意してください。 例えば、Webhookが実行された後、次の訪問では古いデータが表示されますが、再度リロードすると新しいデータが表示されます。

もし、うまくいかない場合は、Webhookのアクティビティログを確認して 200 が返ってきているか、Revalidation処理で指定しているパスが正しいか確認してみてください。

nextjs-revalidate1.png

以上で設定は終了です。
これで、対象のコンテンツが更新された時、該当ページのみ、キャッシュを無効化できます。

関連ドキュメント

NewtMade in Newt