Next.js App Routerを使用したAPIの設定手順
はじめに
完成イメージ
ボタンを押すと、/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を選択
App Routerとは
App RouterはNext.jsのルーティングの新機能です。
/app
ディレクトリ内に配置されたディレクトリやファイルはルーティングの対象となり、ページ遷移を制御します。これにより、従来/pages
ディレクトリで行われていたルーティング作業が、/app
ディレクトリに移行します。
例えば、以下のようなディレクトリ構成の場合、ルートURL(/
)にアクセスするとapp/page.tsx
が表示され、/profile
というURLにアクセスするとapp/profile/page.tsx
が表示されます。
app
├── profile
│ ├── page.tsx
│ ├── layout.tsx
│ └── page.tsx
├── layout.tsx
└── page.tsx
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形式のレスポンスで返す単純なエンドポイントを作成します。
import { NextResponse } from 'next/server';
export async function GET() {
try {
return NextResponse.json({
name: 'Mike',
});
} catch (error) {
throw error
}
データの取得
ボタンを押すと、先ほど作成した/api/user
からJSON形式のレスポンスを取得するように記述しています。
'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)) {
console.error('Axiosのエラーが発生しました:', error);
} else {
console.error('Axios以外のエラーが発生しました:', error);
}
}
};
return (
<div>
<button
onClick={getUserData}
>
名前を取得
</button>
</div>
);
}
axiosをインストールする
npm install axios
動的APIルートの設定
動的なパラメータを持つ API ルートは、ファイル名にブラケット[]
を使って[id]
または[slug]
で定義します。
[id]
または[slug]
が動的な部分であり、これによって動的な値に基づいて異なるリクエストを処理することができます。
ファイル構造
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
)のみを受け付け、固定のデータを返す実装を行っていますが、一般的には、ユーザー情報をデータベースから取得するような実装が多いと思います。
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
に変更しているだけです。
'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クエリパラメータ
終わりに
何かありましたらお気軽にコメント等いただけると助かります。
ここまでお読みいただきありがとうございます🎉
Discussion