Next.jsからSpring Boot APIを叩く — fetchとServer Actions
はじめに
前回はSpring BootでUser CRUDのREST APIを作りました。今回はそのAPIをNext.js側から呼び出します。
Next.js(App Router)でAPIを叩く方法は主に2つです。
| 方法 | 実行場所 | 向いているケース |
|---|---|---|
fetch(Server Component) |
サーバー | 初期表示のデータ取得 |
| Server Actions | サーバー | フォーム送信・データ更新 |
前提:Spring BootのAPIエンドポイント
前回作成したAPIを使います。
GET /api/users → ユーザー一覧
GET /api/users/{id} → ユーザー1件
POST /api/users → ユーザー作成
PUT /api/users/{id} → ユーザー更新
DELETE /api/users/{id} → ユーザー削除
Spring Bootはデフォルト http://localhost:8080 で起動します。
① Server Componentでfetch — 一覧取得
// app/users/page.tsx
type User = {
id: number;
name: string;
email: string;
};
async function getUsers(): Promise<User[]> {
const res = await fetch("http://localhost:8080/api/users", {
cache: "no-store", // 常に最新データを取得
});
if (!res.ok) throw new Error("Failed to fetch users");
return res.json();
}
export default async function UsersPage() {
const users = await getUsers();
return (
<div>
<h1>ユーザー一覧</h1>
<ul>
{users.map((user) => (
<li key={user.id}>
{user.name} — {user.email}
</li>
))}
</ul>
</div>
);
}
Server Componentでは fetch を直接 await できます。cache: "no-store" で毎回最新を取得、cache: "force-cache" でSSGのような静的キャッシュが使えます。
② Server Actionsでデータ作成
// app/users/new/page.tsx
"use server";
import { redirect } from "next/navigation";
async function createUser(formData: FormData) {
"use server";
const name = formData.get("name") as string;
const email = formData.get("email") as string;
const res = await fetch("http://localhost:8080/api/users", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name, email }),
});
if (!res.ok) throw new Error("Failed to create user");
redirect("/users"); // 作成後に一覧へリダイレクト
}
export default function NewUserPage() {
return (
<form action={createUser}>
<input name="name" placeholder="名前" required />
<input name="email" type="email" placeholder="メール" required />
<button type="submit">作成</button>
</form>
);
}
Server Actionsは "use server" ディレクティブをつけた非同期関数です。formの action に渡すとフォーム送信がサーバー側で処理されます。
③ Server Actionsでデータ削除
// app/users/[id]/page.tsx
async function deleteUser(id: number) {
"use server";
await fetch(`http://localhost:8080/api/users/${id}`, {
method: "DELETE",
});
redirect("/users");
}
export default async function UserDetailPage({
params,
}: {
params: { id: string };
}) {
const res = await fetch(`http://localhost:8080/api/users/${params.id}`);
const user = await res.json();
return (
<div>
<h1>{user.name}</h1>
<p>{user.email}</p>
<form action={deleteUser.bind(null, user.id)}>
<button type="submit">削除</button>
</form>
</div>
);
}
環境変数でURLを管理する
ハードコードした http://localhost:8080 は本番で使えません。環境変数で管理します。
# .env.local
NEXT_PUBLIC_API_URL=http://localhost:8080
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/users`);
本番はVercelの環境変数に NEXT_PUBLIC_API_URL=https://api.example.com をセットするだけで切り替えられます。
まとめ
| やりたいこと | 使う方法 |
|---|---|
| ページ表示時にデータ取得 | Server Componentでfetch
|
| フォーム送信・作成・更新・削除 | Server Actions |
| APIのURLを環境別に切り替え |
.env.local + 環境変数 |
次回は CORS対応 — Spring Boot側でNext.jsからのリクエストを許可する設定を整理します。