さとまたwiki

API Routes

Next.jsでバックエンドAPIを作成する

基本的なAPI Route

route.ts の作成

app/api/以下にファイルを作成

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

export async function GET() {
  return NextResponse.json({
    message: 'Hello, World!'
  });
}

// アクセス: GET /api/hello
// レスポンス: { "message": "Hello, World!" }
プレビュー
GET
/api/hello
{ "message": "Hello, World!" }

HTTPメソッド

複数メソッドの定義

GET, POST, PUT, DELETE など

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

// GET: ユーザー一覧を取得
export async function GET() {
  const users = await db.user.findMany();
  return NextResponse.json(users);
}

// POST: 新規ユーザー作成
export async function POST(request: Request) {
  const body = await request.json();
  const user = await db.user.create({
    data: body
  });
  return NextResponse.json(user, { status: 201 });
}
プレビュー
GET /api/users → 一覧取得
POST /api/users → 新規作成
PUT /api/users/1 → 更新
DELETE /api/users/1 → 削除

動的API Route

パラメータを受け取る

[id]でURLパラメータを取得

typescript
// app/api/users/[id]/route.ts
import { NextResponse } from 'next/server';

interface Context {
  params: { id: string }
}

// GET: 特定ユーザーを取得
export async function GET(
  request: Request,
  { params }: Context
) {
  const user = await db.user.findUnique({
    where: { id: params.id }
  });

  if (!user) {
    return NextResponse.json(
      { error: 'User not found' },
      { status: 404 }
    );
  }

  return NextResponse.json(user);
}

// DELETE: ユーザーを削除
export async function DELETE(
  request: Request,
  { params }: Context
) {
  await db.user.delete({
    where: { id: params.id }
  });

  return new NextResponse(null, { status: 204 });
}
プレビュー
/api/users/[id]/route.ts
// /api/users/123
// → params.id = "123"

リクエストの処理

リクエストボディとクエリパラメータ

様々なデータの取得方法

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

export async function GET(request: Request) {
  // クエリパラメータを取得
  const { searchParams } = new URL(request.url);
  const query = searchParams.get('q');
  const limit = searchParams.get('limit') || '10';

  // /api/search?q=hello&limit=5
  // → query = "hello", limit = "5"

  const results = await search(query, parseInt(limit));
  return NextResponse.json(results);
}

export async function POST(request: Request) {
  // JSONボディを取得
  const body = await request.json();

  // フォームデータを取得
  // const formData = await request.formData();
  // const name = formData.get('name');

  // ヘッダーを取得
  const authHeader = request.headers.get('Authorization');

  return NextResponse.json({ received: body });
}
プレビュー
// クエリパラメータ
searchParams.get('q')
// JSONボディ
await request.json()
// ヘッダー
request.headers.get('Authorization')

レスポンスの設定

カスタムレスポンス

ステータスコードやヘッダーを設定

typescript
import { NextResponse } from 'next/server';

export async function GET() {
  // 基本的なJSONレスポンス
  return NextResponse.json({ data: 'value' });

  // ステータスコード付き
  return NextResponse.json(
    { error: 'Not found' },
    { status: 404 }
  );

  // カスタムヘッダー
  return NextResponse.json(
    { data: 'value' },
    {
      status: 200,
      headers: {
        'Cache-Control': 'max-age=3600',
        'X-Custom-Header': 'value'
      }
    }
  );

  // リダイレクト
  return NextResponse.redirect(new URL('/login', request.url));
}
プレビュー
200 OK
201 Created
204 No Content
400 Bad Request
404 Not Found
500 Server Error

ミドルウェア

middleware.ts

リクエストをインターセプト

typescript
// middleware.ts (プロジェクトルート)
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
  // 認証チェック
  const token = request.cookies.get('token');

  if (!token && request.nextUrl.pathname.startsWith('/api/protected')) {
    return NextResponse.json(
      { error: 'Unauthorized' },
      { status: 401 }
    );
  }

  return NextResponse.next();
}

// 適用するパスを指定
export const config = {
  matcher: '/api/:path*'
};
プレビュー
// 全てのAPIリクエストの前に実行
// 認証、ログ、レート制限などに使う