🛝

Next.js App Routerを使用したAPIの設定手順

2024/04/18に公開

はじめに

完成イメージ
ボタンを押すと、/api/userからJSON形式のレスポンスを取得するように記述しています。
[id]または[slug]のような動的APIルートの設定についても後半で記述しています。

Next.jsではAPIルートを設定することで、APIエンドポイントを作成できるのですが、ページを作成するのと同様に、appディレクトリ内にapiディレクトリを作成して、その中にディレクトリとファイルを追加して、APIのコードを記述することで、そのディレクトリ名がAPIのエンドポイントになります。

また、今回はApp Directory構造でプロジェクトの作成時に下記を選択しているため、srcディレクトリを使用しています。
srcディレクトリを使用していない方はsrcの記述を除いてください。

✔ Would you like to use `src/` directory? … No / Yes # Yesを選択

https://nextjs.org/docs/app/building-your-application/routing/route-handlers

https://nextjs.org/docs/app/building-your-application/data-fetching/fetching-caching-and-revalidating

APIディレクトリの作成

src/app以下にapiディレクトリを作成します。

mkdir src/app/api

APIファイルの作成

app/apiフォルダ内にuserというディレクトリとroute.tsファイルを作成します。

ファイル構造

app/
└── api/(APIのエンドポイント)
    └── user/(APIのエンドポイント)
        └── route.ts

このファイルを作成することで/api/userというエンドポイントが生成されます。

mkdir -p src/app/api/user && touch src/app/api/user/route.ts

APIエンドポイントの設定

今回は名前をJSON形式のレスポンスで返す単純なエンドポイントを作成します。

route.ts
import { NextResponse } from 'next/server';

export async function GET() {
  return NextResponse.json({
    name: 'Mike',
  });
}

データの取得

ボタンを押すと、先ほど作成した/api/userからJSON形式のレスポンスを取得するように記述しています。

src/app/page.tsx
'use client';

import axios, { AxiosError } from 'axios';

export default function Home() {
  const getUserData = async () => {
    try {
      const response = await axios.get('/api/user');
      console.log('response', response);
      console.log('response.data', response.data);
    } catch (error) {
      if (axios.isAxiosError(error)) {
        const axiosError = error as AxiosError;
        console.error(
          'APIリクエストでエラーが発生しました:',
          axiosError.response?.data || 'エラー情報が取得できません'
        );
      } else {
        console.error('その他エラーが発生しました:', error);
      }
    }
  };

  return (
      <div>
        <button
          onClick={getUserData}
        >
          名前を取得
        </button>
      </div>
  );
}

動的APIルートの設定

動的なパラメータを持つ API ルートは、ファイル名にブラケット[]を使って[id]または[slug]で定義します。
[id]または[slug]が動的な部分であり、これによって動的な値に基づいて異なるリクエストを処理することができます。
https://nextjs.org/docs/app/building-your-application/routing/route-handlers#dynamic-route-segments

ファイル構造

app/
└── api/(APIのエンドポイント)
    └── user/(APIのエンドポイント)
        └── [id]/(APIのエンドポイント)
            └── route.ts

slugを使用するケース

コンテンツ識別用途:slugは記事やブログポストのようなコンテンツに対して、URL内で意味のある識別子として使用されます。

idを使用するケース

データ識別用途:idはデータベースのレコードを一意に識別するために使用されます。ユーザーや製品などのエンティティ(項目)に対して、CRUD操作(作成、読み取り、更新、削除)をURLを通じて直接行うのに適しています。

APIファイルの作成

先ほど作成したapp/api/userというディレクトリに[id]ディレクトリとroute.tsファイルを作成します。

zshシェルでは、ブラケット[]を使用した表現が、ファイル名のパターンマッチングとして解釈されます。
なので下記では、ファイル名の中でブラケットを使用する場合は、ブラケットを下記のようにエスケープしています。

touch src/app/api/user/\[id\]/route.ts

また、もう一つの方法としては、クォート(シングルクォート'やダブルクォート'')を使用する方法があります。
クォートを使うことで、シェルに対してパス全体が一つの文字列として扱われ、ファイル名の中の特殊文字がエスケープされるため、意図した通りの動作となります。

touch 'src/app/api/user/\[id\]/route.ts'

APIエンドポイントの設定

今回は特定のID(1)のみを受け付け、固定のデータを返す実装を行っていますが、一般的には、ユーザー情報をデータベースから取得するような実装が多いと思います。

user/[id]/route.ts
import { NextRequest, NextResponse } from 'next/server';

export async function GET(
  request: NextRequest,
  { params }: { params: { id: string } }
) {
  const { id } = params;

  if (id === '1') {
    return NextResponse.json({ id: 1, name: 'Mike' });
  } else {
    return new NextResponse(JSON.stringify({ error: '無効なユーザーID' }), {
      status: 404,
      headers: {
        'Content-Type': 'application/json',
      },
    });
  }
}

データの取得

先ほど作成したエンドポイントを/api/user/1に変更しているだけです。

src/app/page.tsx
'use client';

import axios, { AxiosError } from 'axios';

export default function Home() {
  const getUserData = async () => {
    try {
      const response = await axios.get('/api/user/1');
      console.log('response', response);
      console.log('response.data', response.data);
    } catch (error) {![](https://storage.googleapis.com/zenn-user-upload/9caf0c52e6d9-20240418.gif)
      if (axios.isAxiosError(error)) {
        const axiosError = error as AxiosError;
        console.error(
          'APIリクエストでエラーが発生しました:',
          axiosError.response?.data || 'エラー情報が取得できません'
        );
      } else {
        console.error('その他エラーが発生しました:', error);
      }
    }
  };

  return (
      <div>
        <button
          onClick={getUserData}
        >
          名前を取得
        </button>
      </div>
  );
}

今回の場合はエンドポイントを/api/user/11にした場合は、下記のようにエラーになります。

URLクエリパラメータ

https://nextjs.org/docs/app/building-your-application/routing/route-handlers#url-query-parameters

終わりに

何かありましたらお気軽にコメント等いただけると助かります。
ここまでお読みいただきありがとうございます🎉

Discussion