Next.js14でRailsAPIのJsonデータをRouteHandlerを使ってフェッチしたい。
Q&A
Closed
解決したいこと
現在バックにRails、フロントにNext.jsとReactを使用しSPA化したメディア系Webアプリケーションを作成しております。
RailsAPIのusersのJsonデータをNext14のRouteHandlerを使ってフェッチしたいと思っているのですが、Railsサーバーは問題なく稼働しているのにroute.jsのデータ取得が失敗してしまいます。
現在はユーザー一覧表示機能でCSRを使って取得しているデータをSSRに変更しようとしています。
そこでSSRを行うためにRouteHandlerを使用した方法で行おうと考えたのですが、うまくいきません。
本来であればlocalhost:3000/api/v1/usersのデータのフェッチに成功してlocalhost:8000/api/usersにJson形式でデータが表示されるはずだと思ったのですが、そうなりません。
CSRでのデータ取得はうまく行っているのと、普通にlocalhost:3000/api/v1/usersでデータは閲覧できるので、Rails側やCOSEの問題ではないと思っています。
公式ドキュメントやZen、Qiitaの投稿などを調べてみたのですが、RailsSPAでAppRouterを使用している人で、RouteHandlerを使用している人が見つからず、行き詰まってしまいました。
まだ初学者なので、根本的なところで何かを勘違いしているのかもしれません。
なにか解決策かヒントをご教授いただけないでしょうか。
発生している問題・エラー
コンソールログ
users:1
Failed to load resource: the server responded with a status of 404 (Not Found)
具体的には以下のコードでhttp://localhost:8000/api/users にてデータフェッチを確認できません。
import { NextResponse } from "next/server"
// export const GET = () => {
// return NextResponse.json({ hello: "hello" })
// }
export async function GET() {
try {
const res = await fetch('http://localhost:3000/api/v1/users');
if (!res.ok) {
return NextResponse.json({ error: 'Failed to fetch users data' }, { status: res.status });
}
const data = await res.json();
if (!data) {
return NextResponse.json({ error: 'No data returned from the API' }, { status: 500 });
}
return NextResponse.json({ data });
} catch (error) {
console.error('Error fetching users data:', error);
return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 });
}
}
上記の際のブラウザには以下の出力がなされます。
{"error":"Failed to fetch users data"}
現在のCSRでのユーザ一覧ページは以下のように記述されています。
"use client";
import { useEffect, useState } from "react";
import axios from "axios";
const Users = () => {
const [users, setUsers] = useState([]);
const [error, setError] = useState("");
const [currentPage, setCurrentPage] = useState(1);
const [totalPages, setTotalPages] = useState(1);
useEffect(() => {
const getUser = async () => {
try {
const res = await axios.get(
`http://localhost:3000/api/v1/users?page=${currentPage}`,
{
withCredentials: true, // クッキーを含める設定
}
);
if (res.data && Array.isArray(res.data.users)) {
setUsers(res.data.users);
setTotalPages(res.data.total_pages);
} else {
console.error("APIレスポンスは正しくありません:", res.data);
setError("データの取得に失敗しました。");
}
} catch (err) {
console.error("API呼び出しに失敗しました:", err);
setError("データの取得に失敗しました。");
}
};
getUser();
}, [currentPage]); // currentPageが変わるたびに実行される
const renderPageNumbers = () => {
const pages = [];
const maxPagesToShow = 5; // 表示するページ数を制限
const halfWindow = Math.floor(maxPagesToShow / 2);
let startPage = Math.max(currentPage - halfWindow, 1);
let endPage = Math.min(currentPage + halfWindow, totalPages);
if (startPage > 1) {
pages.push(1);
if (startPage > 2) {
pages.push("...");
}
}
for (let i = startPage; i <= endPage; i++) {
pages.push(i);
}
if (endPage < totalPages) {
if (endPage < totalPages - 1) {
pages.push("...");
}
pages.push(totalPages);
}
return pages;
};
const handlePageClick = (page) => {
if (page !== currentPage && typeof page === "number") {
setCurrentPage(page);
}
};
if (error) {
return <div>{error}</div>;
}
return (
<div className="p-4">
{users?.map((user) => (
<div key={user.id} className="bg-white shadow-md rounded-lg p-6 mb-4">
<p className="text-lg font-semibold mb-2">名前: {user.name}</p>
<p className="text-gray-600 mb-1">メールアドレス: {user.email}</p>
<p className="text-gray-600 mb-1">ID: {user.id}</p>
<p className="text-gray-600 mb-1">ポスト数: {user.posts_count}</p>
<p className="text-gray-600">
アカウント作成日: {new Date(user.created_at).toLocaleDateString()}
</p>
</div>
))}
<div className="flex justify-center mt-4">
{renderPageNumbers().map((page, index) => (
<button
key={index}
onClick={() => handlePageClick(page)}
className={`mx-1 px-3 py-1 border rounded ${page === currentPage ? "bg-blue-500 text-white" : "bg-white text-blue-500"}`}
>
{page}
</button>
))}
</div>
</div>
);
};
export default Users;
Githubリンク
コードはfeatureブランチにpushしてあります。
Nextのapp下のディレクトリ構成は以下です
app
├── api
│ ├── posts
│ └── users
│ └── route.js
├── data
│ └── background_image.png
├── diarys
│ ├── [id]
│ │ └── page.jsx
│ ├── components
│ │ ├── EditPostModal.jsx
│ │ ├── PostDelete.jsx
│ │ ├── PostInput.jsx
│ │ ├── PostPagination.jsx
│ │ └── PostView.jsx
│ └── page.jsx
├── edit-password
│ └── page.jsx
├── edit-profile
│ └── page.jsx
├── followers
│ └── page.jsx
├── following
│ └── page.jsx
├── globals.css
├── layout.js
├── mock
├── not-found.js
├── page.jsx
├── rooms
│ └── page.jsx
├── signup
│ └── page.jsx
├── user-profile
│ └── page.jsx
└── users
└── page.jsx
自分で試したこと
ここに問題・エラーに対して試したことを記載してください。
・GPT4oに解決策を聞く
・docker-compose downからの再build,再up
・CORSの設定確認
・Railsログの確認(何も出力されない)
・console.logの設置と確認
・ThunderClientを使用してAPIエンドポイントにGetリクエストを送信(成功)
・http://localhost:3000/api/v1/usersを普通に開く(アクセス成功)
・以下の記事を読んで学習
(下記はUdemyのCodeMafiaさんの2024React/Nextガイドの動画です)