1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Next.jsからSpring Boot APIを叩く — fetchとServer Actions

1
Posted at

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からのリクエストを許可する設定を整理します。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?