🥶

microCMSでコンテンツの更新時にキャッシュをrevalidateする方法

2024/08/04に公開

はじめに

こんにちは!

今回は、Next.js+MicroCMSで、記事更新の際にキャッシュの影響で更新されない問題を解消する方法を紹介します。

細かいコードはgithubで公開しておりますのでご確認ください。
https://github.com/s1f10210273/blog-sample2

背景

Next.js+MicroCMSでの開発中に、microCMS側で記事を更新してもなかなか反映されないという問題に直面しました。
よくよく調べてみたところ、Next.jsのキャッシュの影響で反映がうまくいっていないことがわかりました。
この記事では、Webhookを利用して、キャッシュの再検証を行う方法を紹介したいと思います。

手順

1. microCMSの設定画面からwebhookを作る

api設定からwebhookの画面にいき、「追加」をクリックします。
サービスの選択で、「カスタム通知」を選択します。


シークレットに任意のシークレット値を入力しましょう
僕は、pythonで生成しました

# シークレットを生成
import secrets
random_hex = secrets.token_hex(20)
print(random_hex)

2. webhookからキャッシュをrevalidate

今回は、記事の送信時に指定したAPIにPOSTリクエストを送り、キャッシュの再検証を行なっています。
このAPIはmicroCMSからのリクエストのみを受け取るべきなので、シークレットを設定し検証をしています。
実装方法は以下のようになりました

// src/app/api/route.ts

import { revalidateTag } from "next/cache";
import { NextResponse } from "next/server";
import * as crypto from "crypto";

type RequestBody = {
  id: string | null | undefined;
  api: string;
};

export async function POST(request: Request): Promise<Response> {
  const bodyText = await request.text();
  const { id, api: endpoint } = JSON.parse(bodyText) as RequestBody;
  const bodyBuffer = Buffer.from(bodyText, "utf-8");

  const secret = process.env.MICROCMS_WEBHOOK_SIGNATURE_SECRET;
  const signature = request.headers.get("X-MICROCMS-Signature");

  if (!bodyText || !secret || !signature) {
    console.error("Missing required information.");
    return NextResponse.json({ status: 400, message: "Bad Request" });
  }

  // 値を検証
  const expectedSignature = crypto
    .createHmac("sha256", secret)
    .update(bodyBuffer)
    .digest("hex");

  const isValid = crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );

  if (!isValid) {
    console.error("Invalid signature.");
    return NextResponse.json({ status: 400, message: "Invalid Signature" });
  }

  // キャッシュの再検証
  revalidateTag("articles");
  return NextResponse.json({ message: "Success" });
}

シークレット値は、X-MICROCMS-Signatureというカスタムヘッダーに付与されています。
そこから、取得した値を検証しています。

その後、revalidateTagで指定したタグのキャッシュを再検証しています。

タグは、データ取得関数で設定しています。

// src/libs/microcms.ts
export const getList = async (queries?: MicroCMSQueries) => {
  const listData = await client.getList<Blog>({
    endpoint: "blogs",
    queries,
    customRequestInit: {
      // タグを設定
      next: { tags: ["articles"] },
    },
  });
  return listData;
};

参考文献

https://blog.microcms.io/nextjs13-microcms-rsc/
https://document.microcms.io/manual/webhook-setting#h5701d6d9fe
https://qiita.com/shunuke-y/items/5da0201b588771307e60

Discussion