みなさん、こんにちは!
前回作成したAPIは、/api/helloにアクセスすると決まったメッセージを返すだけでしたが、実際のWebサービスはもっと複雑です。
ユーザーの入力に応じてデータを取得したり、新しいデータをサーバーに送信したりする必要があります。
今回は、前回作ったReactアプリ(クライアント)とNode.jsサーバー(API)を連携させ、「データの取得(GET)」と「データの新規作成(POST)」という、2つの操作をやってみようと思います。
記事のゴール
- ReactとNode.js間で実際にデータをやり取りする
- URLパラメータを使って、特定のデータを取得するGETリクエストを学ぶ
- クライアントからサーバーにデータを送信するPOSTリクエストを学ぶ
- クロスオリジン通信(CORS)という、連携に必須の知識を学ぶ
1. サーバー側の準備:Expressで2つのAPIを作る
前回作成したmy-api-serverフォルダのserver.jsを編集し、機能を追加します。今回は、シンプルな「タスクリスト」のデータを使います。
1.1. Express-CORSの導入
ReactとNode.jsは、デフォルトではセキュリティ上の理由で通信できません。
これは CORS(Cross-Origin Resource Sharing) という仕組みによるものです。これを許可するために、corsというライブラリをインストールします。
ターミナルで、my-api-serverフォルダに移動して実行してください。
npm install cors
1.2. サーバーコードの修正
server.jsの中身をすべて以下のコードに書き換えてください。
// server.js
const express = require('express');
const cors = require('cors'); // ① corsをインポート
const app = express();
const port = 3000;
// ダミーデータ(タスクリスト)
let tasks = [
{ id: 1, title: 'Node.jsの勉強', completed: false },
{ id: 2, title: 'Reactの記事を読む', completed: false },
{ id: 3, title: '休憩する', completed: true }
];
let nextId = 4; // 次に作成するタスクのID
// ミドルウェアの設定
app.use(cors()); // ② 全てのオリジンからのアクセスを許可
app.use(express.json()); // ③ クライアントから送られてきたJSONデータを受け取るための設定
// --- APIエンドポイントの定義 ---
// 1. 全タスクを取得するAPI (GET /api/tasks)
app.get('/api/tasks', (req, res) => {
// すべてのタスクデータをクライアントに返す
res.json(tasks);
});
// 2. 新しいタスクを追加するAPI (POST /api/tasks)
app.post('/api/tasks', (req, res) => {
// ④ クライアントから送られてきたデータ(リクエストボディ)を取得
const newTaskTitle = req.body.title;
if (!newTaskTitle) {
return res.status(400).json({ message: 'タスクのタイトルが必要です' });
}
// 新しいタスクオブジェクトを作成
const newTask = {
id: nextId++,
title: newTaskTitle,
completed: false
};
// サーバー側のデータに追加
tasks.push(newTask);
// クライアントに、作成された新しいタスク情報を返す
res.status(201).json(newTask);
});
// サーバーを起動します
app.listen(port, () => {
console.log(`サーバーが http://localhost:${port} で起動しました`);
});
【コードの解説】
-
app.use(cors()): これにより、Reactが動く別オリジン(例:http://localhost:5173)から、Node.jsサーバー(http://localhost:3000)へアクセスできるようになります。 -
app.use(express.json()): クライアントから送られてくるPOSTリクエストのボディに含まれるJSONデータを、JavaScriptのオブジェクトとして受け取れるようにする設定です。 -
app.get('/api/tasks', ...): タスク一覧を返す、シンプルなGETリクエストのエンドポイントです。 -
app.post('/api/tasks', ...): クライアントからのPOSTリクエストを受け付け、req.body.titleで新しいタスクのタイトルを取得し、サーバー側のデータ(tasks配列)に追加しています。
サーバーを再起動してください。
node server.js
2. クライアント側の準備:Reactでデータ送受信
次に、前回作成したReactアプリ(my-react-app)のコードを修正し、Node.js APIと連携させます。
2.1. Reactコードの修正
my-react-appフォルダのsrc/App.jsxの中身をすべて以下のコードに書き換えてください。
// src/App.jsx
import React, { useState, useEffect } from 'react';
import './App.css';
// APIのエンドポイントURL
const API_URL = 'http://localhost:3000/api/tasks';
function App() {
// タスク一覧を管理するステート
const [tasks, setTasks] = useState([]);
// 新規タスクの入力値を管理するステート
const [newTaskTitle, setNewTaskTitle] = useState('');
// ローディングとエラー
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
// --- 1. GETリクエスト(タスク一覧の取得) ---
const fetchTasks = async () => {
setLoading(true);
setError(null);
try {
const response = await fetch(API_URL); // APIにリクエストを送信
if (!response.ok) {
throw new Error(`HTTPエラー! ステータス: ${response.status}`);
}
const data = await response.json(); // JSON形式でデータを受け取る
setTasks(data); // ステートを更新
} catch (err) {
setError('タスクの取得に失敗しました。');
console.error(err);
} finally {
setLoading(false);
}
};
// コンポーネントが最初に表示されたときにタスクを取得
// 今回はuseEffectを使って自動でデータを取得します
useEffect(() => {
fetchTasks();
}, []); // []が空なので、初回レンダリング時のみ実行されます
// --- 2. POSTリクエスト(タスクの新規作成) ---
const handleAddTask = async () => {
if (!newTaskTitle.trim()) return; // 入力がない場合は何もしない
try {
const response = await fetch(API_URL, {
method: 'POST', // HTTPメソッドをPOSTに指定
headers: {
'Content-Type': 'application/json', // 送信するデータがJSONであることを指定
},
// サーバーに送るデータ(JSON形式に変換)
body: JSON.stringify({ title: newTaskTitle }),
});
if (!response.ok) {
throw new Error('タスクの作成に失敗しました。');
}
const newTask = await response.json(); // サーバーが返した新しいタスク情報を受け取る
// 既存のタスクリストに新しく作成されたタスクを追加
setTasks([...tasks, newTask]);
setNewTaskTitle(''); // 入力フォームをクリア
} catch (err) {
setError(err.message);
console.error(err);
}
};
return (
<div className="App">
<h1>My Task App</h1>
{/* エラー表示 */}
{error && <p style={{ color: 'red' }}>{error}</p>}
{/* タスク新規作成フォーム (POST) */}
<div className="task-form">
<input
type="text"
value={newTaskTitle}
onChange={(e) => setNewTaskTitle(e.target.value)}
placeholder="新しいタスクを入力"
/>
<button onClick={handleAddTask}>タスクを追加 (POST)</button>
</div>
<hr />
{/* タスク一覧表示 (GETの結果) */}
<h2>タスク一覧</h2>
{loading ? (
<p>タスクを読み込み中...</p>
) : (
<ul>
{tasks.map(task => (
<li key={task.id} style={{ textDecoration: task.completed ? 'line-through' : 'none' }}>
[{task.id}] {task.title}
</li>
))}
</ul>
)}
</div>
);
}
export default App;
【コードの解説】
-
useEffectの復活:useEffectを使い、コンポーネントが**最初に表示された時([]が空)**に自動でfetchTasksを呼び出すようにしました。 -
async/await:fetchやresponse.json()は非同期処理ですが、then()を繋げる代わりにasyncとawaitを使うことで、同期的なコードのように分かりやすく書けるようになります。 -
GETリクエスト:
fetch(API_URL)だけで、サーバーからタスク一覧を取得できます。 -
POSTリクエスト:
-
method: 'POST'を指定し、リクエストの種類を伝えます。 -
headers: サーバーに「JSON形式でデータを送るよ」と伝えます。 -
body: JSON.stringify(...): 送りたいJavaScriptオブジェクトを、APIが理解できるJSON文字列に変換して送ります。
-
2.2. アプリの確認
ターミナルが2つ必要です。
-
ターミナル1(Node.jsサーバー):
my-api-serverフォルダでnode server.jsを実行し、サーバーを起動し続けてください。 -
ターミナル2(Reactクライアント):
my-react-appフォルダでnpm run devを実行し、Reactアプリを起動してください。
ブラウザで確認すると、自動でタスク一覧が表示され、新しいタスクを入力してボタンを押すと、リストがリアルタイムで更新されるはずです。
これで、「フロントエンド(React)」と「バックエンド(Node.js)」が連携するアプリケーションを作成することができました!
3. まとめと次のステップ
今回は、Web開発で最も重要なスキルの一つであるクライアント・サーバー間のデータ送受信をマスターしました。
- GET: サーバーからデータを取得する
- POST: クライアントからサーバーへデータを送信する(新規作成)
- CORS: 異なるサーバー間での通信を可能にするための設定
この連携こそが、現代のあらゆるWebサービスの基盤です。
次回は、サーバー側のタスクデータ(tasks配列)をファイルに保存するなど、より実用的な機能を加えていきます。
今回もお疲れ様でした!次回も頑張ってこー!
おまけ
くすりの窓口では、現在インターンや中途採用を募集しています。
気になる方は以下のリンクよりご確認ください。