Next.js では、ページを表示するだけでなく、自分でAPI(データを返すエンドポイント)を作ることもできます。App Router でそれを担うのが Route Handlers(ルートハンドラー)です。route.ts というファイルに GET や POST といった関数を書くだけで、フォームの送信先やデータ取得用のURLを用意できます。この記事では、Route Handlers の基本、GET・POST の書き方、リクエストのデータの受け取り方、そして注意点まで、初心者向けに解説します。
目次
Route Handlers とは
Route Handlers は、App Router でAPIエンドポイント(リクエストを受けてデータを返すURL)を作るための仕組みです。app フォルダの中に route.ts というファイルを置き、その中で HTTP メソッドと同じ名前の関数(GET、POST、PUT、DELETE など)を export します。すると、そのフォルダのパスがそのままAPIのURLになります。たとえば app/api/hello/route.ts は /api/hello というURLで呼び出せます。
GET を作る
まずはデータを返すだけの一番シンプルな例です。GET 関数を export し、Response.json(...) でJSONを返します。
export function GET() {
// JSON を返す(/api/hello にアクセスすると表示される)
return Response.json({ message: "こんにちは" });
}
これだけで、ブラウザや fetch から /api/hello にアクセスすると {"message":"こんにちは"} が返ってきます。Response はブラウザ標準のオブジェクトで、Next.js 独自のものではありません。Response.json() を使うと、JSON文字列への変換と適切なヘッダーの設定をまとめて行ってくれます。
クエリパラメータを受け取る
URLの末尾に付く ?name=太郎 のようなクエリパラメータは、引数で受け取る request から読み取れます。request.nextUrl.searchParams の get メソッドで値を取り出します。
import { NextRequest } from "next/server";
export function GET(request: NextRequest) {
// /api/greet?name=太郎 の「太郎」を取り出す
const name = request.nextUrl.searchParams.get("name") ?? "ゲスト";
return Response.json({ message: `ようこそ、${name}さん` });
}
get("name") はパラメータが無ければ null を返すため、?? "ゲスト" で既定値を用意しています。NextRequest はブラウザ標準の Request を拡張したもので、nextUrl のような便利なプロパティが使えます。
POST でデータを受け取る
フォームの送信やデータの登録には POST を使います。送られてきたJSONは、await request.json() で読み取れます。
import { NextRequest } from "next/server";
export async function POST(request: NextRequest) {
// 送信された JSON を受け取る
const body = await request.json();
const name = body.name;
if (!name) {
// 入力が無ければ 400(Bad Request)を返す
return Response.json({ error: "name は必須です" }, { status: 400 });
}
// ここでデータベースに保存する、などの処理を行う
return Response.json({ id: 1, name }, { status: 201 });
}
Response.json() の第2引数で status を指定すると、ステータスコードを変えられます。エラーなら 400、作成成功なら 201 のように、状況に合ったコードを返すのが作法です。クライアント側からは、次のように fetch で呼び出します。
const res = await fetch("/api/users", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name: "太郎" }),
});
const data = await res.json();
console.log(data); // { id: 1, name: "太郎" }
page.tsx と同じフォルダには置けない
Route Handlers を使うときの、つまずきやすいポイントがあります。同じフォルダに page.tsx と route.ts の両方を置くことはできません。どちらも「そのURLへのアクセスに応答する」役割なので、競合してしまうためです。ページとAPIは、app/blog/page.tsx(ページ)と app/api/blog/route.ts(API)のように、別々のパスに分けて配置しましょう。多くのプロジェクトでは、APIを app/api/ 以下にまとめる構成がよく使われます。
まとめ
Route Handlers は、route.ts に GET や POST といった関数を書くだけで、Next.js の中にAPIを作れる仕組みです。フォルダのパスがそのままURLになり、Response.json() でJSONを返します。クエリパラメータは request.nextUrl.searchParams、POSTされたJSONは await request.json() で受け取ります。ステータスコードは Response.json() の第2引数で指定できます。ただし、同じフォルダに page.tsx と route.ts を同居させられない点には注意してください。フォームの送信先や外部サービスとの連携口として、まずは小さなAPIから作ってみましょう。