Route Handlers
Next.js
API Routes・middleware・認証
Route Handlers
app/api/ での REST エンドポイント定義
import { NextRequest, NextResponse } from 'next/server';
// GET /api/users
export async function GET(request: NextRequest) {
const { searchParams } = request.nextUrl;
const page = Number(searchParams.get('page') ?? 1);
const limit = Number(searchParams.get('limit') ?? 10);
const users = await db.user.findMany({
skip: (page - 1) * limit,
take: limit,
});
return NextResponse.json({ users, page, limit });
}
// POST /api/users
export async function POST(request: NextRequest) {
const body = await request.json();
// バリデーション
if (!body.name || !body.email) {
return NextResponse.json(
{ error: '名前とメールは必須です' },
{ status: 400 }
);
}
const user = await db.user.create({ data: body });
return NextResponse.json(user, { status: 201 });
}import { NextRequest, NextResponse } from 'next/server';
import { notFound } from 'next/navigation';
interface Context { params: { id: string } }
// GET /api/users/:id
export async function GET(req: NextRequest, { params }: Context) {
const user = await db.user.findUnique({ where: { id: Number(params.id) } });
if (!user) return NextResponse.json({ error: 'Not found' }, { status: 404 });
return NextResponse.json(user);
}
// PATCH /api/users/:id
export async function PATCH(req: NextRequest, { params }: Context) {
const body = await req.json();
const user = await db.user.update({
where: { id: Number(params.id) },
data: body,
});
return NextResponse.json(user);
}
// DELETE /api/users/:id
export async function DELETE(req: NextRequest, { params }: Context) {
await db.user.delete({ where: { id: Number(params.id) } });
return new NextResponse(null, { status: 204 });
}Middleware
認証・リダイレクト・ヘッダー操作
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
const { pathname } = request.nextUrl;
const token = request.cookies.get('token')?.value;
// 認証チェック
const isProtected = pathname.startsWith('/dashboard') ||
pathname.startsWith('/admin');
if (isProtected && !token) {
const loginUrl = new URL('/login', request.url);
loginUrl.searchParams.set('from', pathname); // リダイレクト元を保存
return NextResponse.redirect(loginUrl);
}
// ロール確認
if (pathname.startsWith('/admin')) {
const payload = decodeToken(token!);
if (payload?.role !== 'admin') {
return NextResponse.redirect(new URL('/403', request.url));
}
}
// レスポンスヘッダーを追加
const response = NextResponse.next();
response.headers.set('X-Frame-Options', 'DENY');
return response;
}
// Middleware を適用するパス
export const config = {
matcher: ['/dashboard/:path*', '/admin/:path*', '/api/:path*'],
};