ClaudeNext.jsFeb 28, 2025, 2:00 PM

Building APIs with Next.js

A condensed section focused on the key takeaways first.

Original Post

Quick Digest

Summary

A condensed section focused on the key takeaways first.

claudeenmodel: claude-sonnet-4-20250514

Building APIs with Next.js App Router and Route Handlers

Key Points

  • App Router introduces Route Handlers with Web Standard APIs
  • Single route.ts file can export multiple HTTP methods
  • Built-in support for dynamic routing and proxy patterns

Summary

This comprehensive guide covers building APIs with Next.js using the modern App Router approach and Route Handlers. The guide demonstrates how to create server-side API endpoints that leverage Web Standard Request/Response APIs instead of Node.js-specific implementations.

Key Points

  • App Router vs Pages Router: App Router uses app/ directory with route.ts files and Web Standard APIs, replacing the legacy pages/api/* approach
  • Route Handlers: Export multiple HTTP methods (GET, POST, PUT, DELETE) from a single route.ts file
  • Dynamic Routing: Use folder structure like app/api/users/[id]/route.ts to handle parameterized endpoints
  • Web APIs Integration: Direct access to Request/Response objects, query parameters, headers, and cookies
  • Proxy Layer: Use Next.js as a Backend-for-Frontend (BFF) to proxy external services and handle authentication
  • Shared Middleware: Create reusable wrapper functions for common logic like authentication and logging
  • Deployment Options: Standard Node.js deployment supports full API functionality, while static export mode has limitations
  • When to Skip APIs: Server Components can fetch data directly without exposing public endpoints for internal-only data

Setup Example

// app/api/users/route.ts
export async function GET(request: Request) {
  const users = [{ id: 1, name: 'Alice' }];
  return new Response(JSON.stringify(users), {
    headers: { 'Content-Type': 'application/json' }
  });
}

Full Translation

Translations

A translation section that keeps the flow of the original article.

claudejamodel: claude-sonnet-4-20250514

Next.jsでAPIを構築する

このガイドでは、Next.jsでAPIを構築する方法について説明します。プロジェクトのセットアップ、App RouterとRoute Handlersの理解、複数のHTTPメソッドの処理、動的ルーティングの実装、再利用可能なミドルウェアロジックの作成、そして専用のAPIレイヤーをいつ立ち上げるかの判断について説明します。

1. はじめに

1.1 Next.jsアプリの作成

新しく始める場合は、以下のコマンドで新しいNext.jsプロジェクトを作成できます:

npx create-next-app@latest --api

注意: --apiフラグを使用すると、新しいプロジェクトのapp/フォルダにroute.tsの例が自動的に含まれ、APIエンドポイントの作成方法が示されます。

1.2 App Router vs. Pages Router

Pages Router: 従来、Next.jsはAPIにpages/api/*を使用していました。このアプローチはNode.jsのrequest/responseオブジェクトとExpress風のAPIに依存していました。

App Router(デフォルト): Next.js 13で導入されたApp Routerは、Web標準のRequest/Response APIを完全に採用しています。pages/api/*の代わりに、app/ディレクトリ内の任意の場所にroute.tsまたはroute.jsファイルを配置できるようになりました。

なぜ切り替えるのか? App Routerの「Route Handlers」は、Node.js固有のAPIではなく、Web PlatformのRequest/Response APIに依存しています。これにより学習が簡素化され、摩擦が減り、異なるツール間で知識を再利用できるようになります。

2. Next.jsでAPIを構築する理由(とタイミング)

複数のクライアント向けのパブリックAPI

Next.jsウェブアプリ、別のモバイルアプリ、またはサードパーティサービスによって消費されるパブリックAPIを構築できます。例えば、ReactウェブサイトとReact Nativeモバイルアプリの両方で/api/usersからフェッチすることができます。

既存のバックエンドへのプロキシ

外部のマイクロサービスを単一のエンドポイントの背後に隠したり統合したりしたい場合があります。Next.jsのRoute Handlersは、他の既存のバックエンドへのプロキシまたは中間レイヤーとして機能できます。

WebhookとIntegration

外部からのコールバックやwebhook(例:Stripe、GitHub、Twilio)を受信する場合、Route Handlersで処理できます。

カスタム認証

セッション、トークン、その他の認証ロジックが必要な場合、Next.jsのAPIレイヤーでクッキーの保存、ヘッダーの読み取り、適切なデータでの応答ができます。

注意: 自分のNext.jsアプリのためだけにサーバーサイドデータフェッチが必要で(そのデータを外部で共有する必要がない)場合、Server Componentsがレンダリング中に直接データをフェッチするのに十分かもしれません—別のAPIレイヤーは不要です。

3. Route Handlersを使用したAPIの作成

3.1 基本的なファイル設定

App Router(app/)では、ルートを表すフォルダを作成し、その中にroute.tsファイルを配置します。例えば、/api/usersにエンドポイントを作成するには:

app
└── api
    └── users
        └── route.ts

3.2 1つのファイルでの複数のHTTPメソッド

Pages Router APIルート(単一のデフォルトエクスポートを持つ)とは異なり、同じファイルから異なるHTTPメソッドを表す複数の関数をエクスポートできます。

// app/api/users/route.ts
export async function GET(request: Request) {
  // 例:ここでDBからデータをフェッチ
  const users = [
    { id: 1, name: 'Alice' },
    { id: 2, name: 'Bob' }
  ];
  
  return new Response(JSON.stringify(users), {
    status: 200,
    headers: { 'Content-Type': 'application/json' }
  });
}

export async function POST(request: Request) {
  // リクエストボディを解析
  const body = await request.json();
  const { name } = body;
  
  // 例:新しいユーザーをDBに挿入
  const newUser = { id: Date.now(), name };
  
  return new Response(JSON.stringify(newUser), {
    status: 201,
    headers: { 'Content-Type': 'application/json' }
  });
}

4. Web APIの操作

4.1 RequestとResponseの直接使用

デフォルトでは、Route Handlerメソッド(GETPOSTなど)は標準のRequestオブジェクトを受け取り、標準のResponseオブジェクトを返す必要があります。

4.2 クエリパラメータ

// app/api/search/route.ts
import { NextRequest } from 'next/server';

export function GET(request: NextRequest) {
  const searchParams = request.nextUrl.searchParams;
  const query = searchParams.get('query');
  // 例:`/api/search?query=hello`
  
  return new Response(
    JSON.stringify({ result: `You searched for: ${query}` }),
    {
      headers: { 'Content-Type': 'application/json' },
    },
  );
}

4.3 ヘッダーとクッキー

// app/api/auth/route.ts
import { NextRequest } from 'next/server';
import { cookies, headers } from 'next/headers';

export async function GET(request: NextRequest) {
  // 1. 'next/headers'ヘルパーの使用
  const cookieStore = await cookies();
  const token = cookieStore.get('token');
  const headersList = await headers();
  const referer = headersList.get('referer');
  
  // 2. 標準Web APIの使用
  const userAgent = request.headers.get('user-agent');
  
  return new Response(
    JSON.stringify({ token, referer, userAgent }),
    {
      headers: { 'Content-Type': 'application/json' },
    }
  );
}

5. 動的ルート

動的パス(例:/api/users/:id)を作成するには、フォルダ構造でDynamic Segmentsを使用します:

app
└── api
    └── users
        └── [id]
            └── route.ts
// app/api/users/[id]/route.ts
import { NextRequest } from 'next/server';

export async function GET(
  request: NextRequest,
  { params }: { params: Promise<{ id: string }> },
) {
  const id = (await params).id;
  
  // 例:ID `id`のユーザーをデータベースで検索
  return new Response(
    JSON.stringify({ id, name: `User ${id}` }),
    {
      status: 200,
      headers: { 'Content-Type': 'application/json' },
    }
  );
}

6. Next.jsをプロキシまたは転送レイヤーとして使用

既存のバックエンドサービスをプロキシする一般的なシナリオです。リクエストを認証し、ログを処理し、リモートサーバーやバックエンドに送信する前にデータを変換できます:

// app/api/external/route.ts
import { NextRequest } from 'next/server';

export async function GET(request: NextRequest) {
  const response = await fetch('https://example.com/api/data', {
    // オプション:一部のヘッダーを転送、認証トークンを追加など
    headers: {
      Authorization: `Bearer ${process.env.API_TOKEN}`
    },
  });
  
  // レスポンスを変換または転送
  const data = await response.json();
  const transformed = {
    ...data,
    source: 'proxied-through-nextjs'
  };
  
  return new Response(JSON.stringify(transformed), {
    headers: { 'Content-Type': 'application/json' },
  });
}

7. 共有「ミドルウェア」ロジックの構築

複数のRoute Handlerで同じロジック(認証チェック、ログなど)を適用したい場合、ハンドラーをラップする再利用可能な関数を作成できます:

// lib/with-auth.ts
import { NextRequest } from 'next/server';

type Handler = (req: NextRequest, context?: any) => Promise<Response>;

export function withAuth(handler: Handler): Handler {
  return async (req, context) => {
    const token = req.cookies.get('token')?.value;
    
    if (!token) {
      return new Response(
        JSON.stringify({ error: 'Unauthorized' }),
        {
          status: 401,
          headers: { 'Content-Type': 'application/json' },
        }
      );
    }
    
    // 認証されている場合、元のハンドラーを呼び出し
    return handler(req, context);
  };
}

8. デプロイメントと「SPAモード」の考慮事項

8.1 標準Node.jsデプロイメント

next startを使用した標準のNext.jsサーバーデプロイメントでは、Route Handlers、Server Components、Middlewareなどの機能を使用でき、動的なリクエスト時情報を活用できます。追加の設定は不要です。

8.2 SPA/静的エクスポート

Next.jsは、サイト全体を静的なSingle-Page Application(SPA)として出力することもサポートしています:

// next.config.ts
import type { NextConfig } from 'next';

const nextConfig: NextConfig = {
  output: 'export',
};

export default nextConfig;

静的エクスポートモードでは、Next.jsは純粋に静的なHTML、CSS、JSを生成します。サーバーサイドコード(APIエンドポイントなど)は実行できません。

8.3 VercelでのAPIデプロイ

Next.jsアプリケーションをVercelにデプロイする場合、APIのデプロイに関するガイドがあります。これには、Vercel Firewallを通じたプログラマティックなレート制限などの他のVercel機能も含まれます。

9. APIエンドポイントの作成をスキップするタイミング

App RouterのReact Server Componentsを使用すると、パブリックエンドポイントを公開することなく、サーバー上で直接データをフェッチできます:

// app/users/page.tsx
// (Server Component)
export default async function UsersPage() {
  // このフェッチはサーバー上で実行される(クライアントサイドコードは不要)
  const res = await fetch('https://api.example.com/users');
  const data = await res.json();
  
  return (
    <main>
      <h1>Users</h1>
      <ul>
        {data.map((user: any) => (
          <li key={user.id}>{user.name}</li>
        ))}
      </ul>
    </main>
  );
}

データがNext.jsアプリ内でのみ使用される場合、パブリックAPIは全く必要ないかもしれません。

10. すべてをまとめる

  1. 新しいNext.jsプロジェクトを作成:npx create-next-app@latest --api
  2. app/ディレクトリ内にRoute Handlersを追加(例:app/api/users/route.ts
  3. 同じファイルでHTTPメソッド(GETPOSTPUTDELETEなど)をエクスポート
  4. Web標準APIを使用してRequestオブジェクトと対話し、Responseを返す
  5. 他のクライアントがデータを消費する必要がある場合、またはバックエンドサービスをプロキシする場合は、パブリックAPIを構築

結論

Next.jsのRoute Handlersは、モダンなWeb標準を活用してAPIを構築するための強力で柔軟な方法を提供します。プロキシレイヤーから完全なAPIまで、様々なユースケースに対応できます。

よくある質問

Server Actionsについてはどうですか?

Server ActionsはフォームやミューテーションのためのNext.js固有の機能で、Route Handlersと組み合わせて使用できます。

Route HandlersでTypeScriptを使用できますか?

はい、Route HandlersはTypeScriptを完全にサポートしており、型安全性を提供します。

認証のベストプラクティスは何ですか?

JWT、セッション、またはサードパーティ認証プロバイダーを使用し、適切なミドルウェアパターンを実装することが推奨されます。