Skip to content

Next.jsのApp RouterにおけるAPIルート設定

Next.jsのApp Router(appディレクトリ)では、APIルートの設定方法がpagesディレクトリとは異なります。2023年2月以降のバージョン(特に13.2以降)で導入されたRoute Handlersを使用することで、モダンなAPIエンドポイントを実装できます。

問題点:App Routerへの移行時のエラー

伝統的なpages/apiディレクトリにあるAPIルート(例: pages/api/accounts/login.js)をApp Router(appディレクトリ)に移動しようとすると、以下のエラーが発生します:

Server Error
Error: Cannot find module for page: /api/accounts/login

この原因は:

  • App Routerがpage.jsの代わりにroute.js/route.tsを使用する
  • ファイル配置パスが異なる(app/api/[エンドポイント]/route.js構造が必要)
  • 関数のエクスポート方法が変更されている

解決策:Route Handlersの使用

App RouterでAPIルートを作成する正しい方法は以下の通りです:

  1. ディレクトリ構造の作成
    APIエンドポイントに対応するディレクトリをapp/api以下に作成し、route.jsまたはroute.tsファイルを配置します:

    app/
    ├── api/
    │   └── accounts/
    │       └── login/
    │           └── route.js  ← 重要
  2. HTTPメソッドごとの関数をエクスポート
    route.jsファイルで、対応するHTTPメソッド名の関数をエクスポート:

    javascript
    // app/api/accounts/login/route.js
    import { NextResponse } from 'next/server';
    
    // GETリクエストのハンドリング
    export async function GET(request) {
      console.log(await request.json());
      return NextResponse.json({ status: 'success' }, { status: 200 });
    }
    
    // POSTリクエストのハンドリング
    export async function POST(request) {
      const data = await request.json();
      // ログイン処理など...
      return NextResponse.json({ message: 'Logged in' }, { status: 201 });
    }
  3. エンドポイントへのアクセス
    上記の例では以下のURLでアクセス可能:

    http://localhost:3000/api/accounts/login

重要な注意点

WARNING

  • ファイル名は必ず**route.js**(TypeScriptならroute.ts)にしてください。page.jshandler.jsなどでは機能しません
  • requestオブジェクトはWeb標準のRequest APIを実装
  • レスポンス生成にはNextResponseを使用します

コードの完全例 (TypeScript版)

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

type ResponseData = {
  message: string;
  timestamp: number;
};

export async function GET(req: Request) {
  // クエリパラメータ取得例
  const url = new URL(req.url);
  const name = url.searchParams.get('name') || 'Guest';

  return NextResponse.json<ResponseData>({
    message: `Hello, ${name}!`,
    timestamp: Date.now()
  }, {
    status: 200,
    headers: { 'Cache-Control': 'public, max-age=60' }
  });
}

export async function POST(req: Request) {
  // リクエストボディ取得例
  const body = await req.json();
  
  if(!body.email) {
    return NextResponse.json(
      { error: 'Email is required' },
      { status: 400 }
    );
  }
  
  // DB操作など...
  return NextResponse.json({ 
    success: true, 
    data: { ...body, id: Date.now() }
  });
}

従来方式との主な違い

特徴Pages Router (pages/api)App Router (app/api)
ファイル名[endpoint].jsroute.js
HTTPメソッドreq.methodで分岐各メソッドごとに個別関数 (GET, POSTなど)
レスポンス生成Node.js形式 (res.status(200).json())NextResponse.json()
静的エクスポート可能現時点で不可
エッジ環境設定可能デフォルトでエッジ互換

トラブルシューティング

  • 404エラーが発生する場合:
    1. ファイル名がroute.jsになっているか確認
    2. ディレクトリ構造がapp/api/[endpoint]/route.jsになっているか確認
    3. 再ビルドを実行: npm run buildnpm start

段階的な移行のすすめ

既存プロジェクトを移行する場合:

  1. apppagesディレクトリを併存可能
  2. 特定エンドポイントから順次移行
  3. next.config.jsで両形式をサポート:
    js
    module.exports = {
      experimental: {
        appDir: true, // App Router有効
      },
    }

ベストプラクティス

  1. 関数の分割
    ビジネスロジックは別ファイルに切り出し:

    js
    // utils/auth.js
    export async function authenticate(credentials) {
      /* 認証ロジック */
    }
    
    // app/api/login/route.js
    import { NextResponse } from 'next/server';
    import { authenticate } from '@/utils/auth';
    
    export async function POST(request) {
      const credentials = await request.json();
      const user = await authenticate(credentials);
      return NextResponse.json(user);
    }
  2. エラーハンドリング
    共通エラーハンドラを使用:

    js
    export async function GET(request) {
      try {
        throw new Error('Test error');
      } catch (error) {
        return NextResponse.json(
          { error: error.message },
          { status: 500 }
        );
      }
    }
  3. APIルートの推奨フロー

App RouterのAPIルートは、モダンなWeb標準に準拠しつつ、Next.jsの最新機能を活用できます。バージョンアップに伴う仕様変更があるため、公式ドキュメントで常に最新情報を確認してください。