0
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?

React+Node.js(node-postgres)でRDS上のPostgreSQLと連携する

Last updated at Posted at 2025-03-30

概要

Reactで作ったUIからNode.jsで構えてるAPIを叩き、RDS上のデータを検索して表示するサンプル。
「React RDS 接続」でググったら SpringBoot を使う例しか出てこなくて困ったので、備忘録として記事を作成した。

構成

Frontend (React) → Backend (Node.js + Express) → PostgreSQL(AWS RDS)

バックエンド

Node.js準備。expressとnode-postgresをインストール。

mkdir backend && cd backend
npm init -y
npm install express pg cors dotenv

バックエンドはindex.jsのみ作成。フロントから受け渡された検索クエリをもとに、RDSを検索、結果を返答する。
ここではRDS上のユーザーをIDで検索する想定。

index.jsx
const express = require('express');
const { Pool } = require('pg');
const cors = require('cors');
require('dotenv').config();

const app = express();
const port = 4000;

const pool = new Pool({
    user: process.env.DB_USER,
    host: process.env.DB_HOST,
    database: process.env.DB_DATABASE,
    password: process.env.DB_PASSWORD,
    port: process.env.DB_PORT,
});

app.use(cors());

app.get('/api/users', async (req, res) => {
  // 検索クエリをセット
  const search = req.query.search;
    
  let query = 'SELECT * FROM '+ process.env.DB_TABLE;
  const params = [];

  if (search) {
    query += ' WHERE id = $1';
    params.push(`%${search}%`);
  }

    try {
        // RDSインスタンスに接続
        const result = await pool.query(query, params);
        res.json(result.rows);
    } catch (error) {
        console.error(error);
        res.status(500).send('Server Error');
    }
});

app.listen(port, () => {
    console.log(`Server running on port ${port}`);
});

.env
DB_USER=username
DB_PASSWORD=password
DB_HOST=rds_endpoint
DB_PORT=5432
DB_DATABASE=dbname
DB_TABLE=tablename

想定しているRDSの中身

RDSの中身
 [
     {
        "id": 1,
        "name": "田中太郎",
        "email": "tanaka@example.com"
    },
    {
        "id": 2,
        "name": "鈴木花子",
        "email": "suzuki@example.com"
    }
]

フロントエンド

セットアップ。Vite使用。tailwindはv4から色々変わっているので注意。

npm create vite@latest frontend -- --template react
cd frontend
npm install
npm install axios
npm install tailwindcss @tailwindcss/vite

メイン画面作成。検索ボックスと検索結果を表示するだけのシンプル構成。
UIセンス皆無なのでcssは生成AIにお任せした。

src/components/UserList.jsx
import React, { useState, useEffect } from 'react';
import axios from 'axios';

const UsersList = () => {
  const [users, setUsers] = useState([]);
  const [searchTerm, setSearchTerm] = useState('');

  useEffect(() => {
    fetchUsers();
  }, []);

  const fetchUsers = (query = '') => {
    axios.get(`http://localhost:4000/api/users?search=${query}`)
      .then(res => setUsers(res.data))
      .catch(err => console.error(err));
  };

  const handleSearch = (e) => {
    e.preventDefault();
    fetchUsers(searchTerm);
  };

  return (
    <div className="min-h-screen bg-gray-100 py-10 px-4 sm:px-6 lg:px-8">
      <div className="max-w-4xl mx-auto bg-white shadow-xl rounded-2xl overflow-hidden">
        <div className="px-6 py-5 bg-gradient-to-r from-blue-500 to-indigo-600">
          <h2 className="text-2xl font-bold text-white">ユーザー一覧</h2>
        </div>
        {/* 検索フォーム */}
        <form onSubmit={handleSearch} className="mb-4 flex">
          <input
            type="text"
            placeholder="IDを入力して検索..."
            className="flex-grow px-4 py-2 border border-gray-300 rounded-l-md focus:outline-none"
            value={searchTerm}
            onChange={(e) => setSearchTerm(e.target.value)}
          />
          <button
            type="submit"
            className="px-4 py-2 bg-blue-500 text-white rounded-r-md hover:bg-blue-600"
          >
            検索
          </button>
        </form>
        {/* 検索結果表示 */}
        <div className="p-6">
          <table className="min-w-full divide-y divide-gray-200">
            <thead className="bg-gray-50">
              <tr>
                <th className="px-6 py-3 text-left text-sm font-semibold text-gray-600 uppercase tracking-wider">
                    ID
                </th>
                <th className="px-6 py-3 text-left text-sm font-semibold text-gray-600 uppercase tracking-wider">
                    名前
                </th>
                <th className="px-6 py-3 text-left text-sm font-semibold text-gray-600 uppercase tracking-wider">
                    メール
                </th>
              </tr>
            </thead>
            <tbody className="divide-y divide-gray-200">
              {users.map(user => (
                <tr key={user.id} className="hover:bg-gray-50">
                  <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-700">
                      {user.id}
                  </td>
                  <td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">
                      {user.name}
                  </td>
                  <td className="px-6 py-4 whitespace-nowrap text-sm text-blue-500">
                      {user.email}
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </div>
    </div>
  );
};

export default UsersList;

tailwind使用準備。設定を追加する。
詳細は公式ドキュメント参照。

App.css
+ @import "tailwindcss";

#root {
  max-width: 1280px;
  margin: 0 auto;
  padding: 2rem;
  text-align: center;
}
App.jsx
import React from 'react';
+ import './App.css';
import UsersList from './components/UsersList';

function App() {
  return (
    <UsersList />
  );
}

export default App;
vite.config.js
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
+ import tailwindcss from '@tailwindcss/vite'

export default defineConfig({
  plugins: [
    react(),
+    tailwindcss(),
  ],
})

実行結果

image.png

参考:フォルダ構成

記述に以下を使わせてもらった。便利。

.
├── backend/
│   ├── index.js
│   └── .env
└── frontend/
    ├── src/
    │   ├── components/
    │   │   └── UserList.jsx
    │   ├── App.jsx
    │   └── App.css
    └── vite.config.js
0
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
0
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?