Next.jsのDraft Modeでコンテンツをプレビューする方法
Draft Modeを使用すると、Next.jsアプリケーションでheadless CMSからドラフトコンテンツをプレビューできます。これはビルド時に生成される静的ページに対して便利です。Draft Modeを使用すると、動的レンダリングに切り替えて、サイト全体を再構築することなくドラフトの変更を確認できます。
このページでは、Draft Modeを有効にして使用する方法について説明します。
ステップ1:Route Handlerを作成する
Route Handlerを作成してください。任意の名前を付けることができます。例えばapp/api/draft/route.tsなどです。
export async function GET(request: Request) {
  return new Response('')
}次に、draftMode関数をインポートして、enable()メソッドを呼び出してください。
import { draftMode } from 'next/headers'
 
export async function GET(request: Request) {
  const draft = await draftMode()
  draft.enable()
  return new Response('Draft mode is enabled')
}これにより、Draft Modeを有効にするためのcookieが設定されます。このcookieを含む後続のリクエストはDraft Modeをトリガーし、静的に生成されたページの動作を変更します。
/api/draftにアクセスしてブラウザーの開発者ツールを確認することで、これを手動でテストできます。__prerender_bypassという名前のcookieを含むSet-Cookieレスポンスヘッダーに気づくでしょう。
ステップ2:Headless CMSからRoute Handlerにアクセスする
これらのステップは、使用しているheadless CMSがカスタムドラフトURLの設定をサポートしていることを想定しています。サポートしていない場合でも、この方法を使用してドラフトURLを保護できますが、ドラフトURLを手動で構築してアクセスする必要があります。具体的なステップは、使用するheadless CMSによって異なります。
Headless CMSからRoute Handlerに安全にアクセスするには:
- トークンジェネレータを使用して秘密トークン文字列を作成してください。この秘密はNext.jsアプリケーションとheadless CMSのみが知っているものです。
 - Headless CMSがカスタムドラフトURLの設定をサポートしている場合、ドラフトURL(Route Handlerが
app/api/draft/route.tsにあることを想定)を指定してください。例えば: 
https://<your-site>/api/draft?secret=<token>&slug=<path>
<your-site>はデプロイメントドメインである必要があります。<token>は生成した秘密トークンに置き換えてください。<path>は表示したいページのパスである必要があります。/posts/oneを表示したい場合は、&slug=/posts/oneを使用してください。Headless CMSではドラフトURLに変数を含めることができるため、
<path>をCMSのデータに基づいて動的に設定できる場合があります。例えば、&slug=/posts/{entry.fields.slug}のようにです。
- Route Handlerで、秘密が一致することと
slugパラメータが存在することを確認してください。存在しない場合はリクエストが失敗する必要があります。draftMode.enable()を呼び出してcookieを設定し、slugで指定されたパスにブラウザーをリダイレクトしてください: 
import { draftMode } from 'next/headers'
import { redirect } from 'next/navigation'
 
export async function GET(request: Request) {
  // クエリ文字列パラメータを解析する
  const { searchParams } = new URL(request.url)
  const secret = searchParams.get('secret')
  const slug = searchParams.get('slug')
 
  // 秘密とパラメータを確認する
  // この秘密はこのRoute Handlerとコンテンツ管理システムのみが知っているものです
  if (secret !== 'MY_SECRET_TOKEN' || !slug) {
    return new Response('Invalid token', { status: 401 })
  }
 
  // Headless CMSをフェッチして、提供された`slug`が存在するかを確認する
  // getPostBySlugはheadless CMSへの必要なフェッチロジックを実装します
  const post = await getPostBySlug(slug)
 
  // slugが存在しない場合、Draft Modeが有効になるのを防ぐ
  if (!post) {
    return new Response('Invalid slug', { status: 401 })
  }
 
  // cookieを設定してDraft Modeを有効にする
  const draft = await draftMode()
  draft.enable()
 
  // フェッチされたpostのパスにリダイレクトする
  // searchParams.slugにリダイレクトすると、オープンリダイレクトの脆弱性につながる可能性があるため、リダイレクトしません
  redirect(post.slug)
}成功すると、ブラウザーはDraft Modeのcookieを含む表示したいパスにリダイレクトされます。
ステップ3:ドラフトコンテンツをプレビューする
次のステップは、draftMode().isEnabledの値を確認するようにページを更新することです。
cookieが設定されているページをリクエストすると、データはリクエスト時間に(ビルド時ではなく)フェッチされます。
さらに、isEnabledの値はtrueになります。
// データをフェッチするページ
import { draftMode } from 'next/headers'
 
async function getData() {
  const { isEnabled } = await draftMode()
 
  const url = isEnabled
    ? 'https://draft.example.com'
    : 'https://production.example.com'
 
  const res = await fetch(url)
 
  return res.json()
}
 
export default async function Page() {
  const { title, desc } = await getData()
 
  return (
    <main>
      <h1>{title}</h1>
      <p>{desc}</p>
    </main>
  )
}Headless CMSからドラフトRoute Handler(secretとslugを含む)にアクセスするか、URLを使用して手動でアクセスすると、ドラフトコンテンツが表示されるようになります。また、ドラフトを公開せずに更新すると、ドラフトを表示できるようになります。