Day 27 已經建立了排班專題需要的 employees 與 schedules Table。
之前 Node.js 雖然可以直接查詢 PostgreSQL,但真正的系統通常不會讓前端直接操作資料庫,而是透過後端 API 處理。
整體架構會變成:
前端
│
│ HTTP Request
↓
Node.js API
│
│ SQL
↓
PostgreSQL
│
↓
employees / schedules
今天就要建立簡單的 Express API,讓程式可以透過 API 取得與新增員工資料。
首先在 Node.js 專案中安裝 Express:
npm install express
之前已經安裝過:
npm install pg dotenv
因此目前會使用到:
express → 建立 API
pg → 連線 PostgreSQL
dotenv → 讀取環境變數
先建立基本的 Express 與 PostgreSQL 連線:
require("dotenv").config();
const express = require("express");
const { Pool } = require("pg");
const app = express();
app.use(express.json());
const pool = new Pool({
host: process.env.DB_HOST,
port: Number(process.env.DB_PORT),
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME
});
app.listen(3000, () => {
console.log("Server running on port 3000");
});
這次使用的是:
Pool
而不是 Day 24 使用的 Client。
因為 API 會不斷收到不同 Request,使用 Pool 可以管理與重複使用資料庫連線,比每次 Request 都重新建立一個 Client 更適合後端服務。
第一個 API 用來取得所有員工資料:
app.get("/employees", async (req, res) => {
try {
const result = await pool.query(
"SELECT * FROM employees ORDER BY id"
);
res.json(result.rows);
} catch (err) {
console.error(err);
res.status(500).json({
message: "取得員工資料失敗"
});
}
});
當使用者請求:
GET /employees
Node.js 就會執行:
SELECT * FROM employees ORDER BY id;
最後將 PostgreSQL 查詢結果轉成 JSON 回傳。
整個流程可以整理成:
GET /employees
│
↓
Express
│
↓
SELECT * FROM employees
│
↓
PostgreSQL
│
↓
result.rows
│
↓
JSON Response
例如回傳:
[
{
"id": 1,
"name": "小明",
"employee_type": "正職"
},
{
"id": 2,
"name": "小美",
"employee_type": "兼職"
}
]
除了查詢員工,也可以建立新增員工的 API:
app.post("/employees", async (req, res) => {
const { name, employee_type } = req.body;
try {
const result = await pool.query(
`INSERT INTO employees (name, employee_type)
VALUES ($1, $2)
RETURNING *`,
[name, employee_type]
);
res.status(201).json(result.rows[0]);
} catch (err) {
console.error(err);
res.status(500).json({
message: "新增員工失敗"
});
}
});
前端只需要送出:
{
"name": "小雨",
"employee_type": "兼職"
}
Node.js 就會將資料新增到 PostgreSQL。
這次沒有直接把變數放進 SQL:
`INSERT INTO employees VALUES ('${name}', '${employee_type}')`
而是使用:
VALUES ($1, $2)
再另外傳入:
[name, employee_type]
這種方式叫做 Parameterized Query(參數化查詢)。
除了讓 SQL 與資料分開之外,也可以降低 SQL Injection 的風險,因此使用者輸入的資料不應直接拼接到 SQL 字串中。
如果 Node.js 也在 Docker Compose 中,可以替 app 加入 Port:
app:
build: .
container_name: my-node-app
ports:
- "3000:3000"
env_file:
- .env
depends_on:
- postgres
接著重新建立:
docker compose up -d --build
現在就可以透過:
localhost:3000
存取 Node.js API。
例如:
GET http://localhost:3000/employees
做到這裡,排班專題已經開始形成完整的前後端資料流程:
瀏覽器 / 前端
│
│ localhost:3000
↓
Node.js + Express
│
│ postgres:5432
↓
PostgreSQL
│
├── employees
└── schedules
前端不需要知道 PostgreSQL 的帳號密碼,只需要透過 API 與後端溝通。
req.body 取得不到資料 → ✅ 加入 app.use(express.json())
.env 與 DB_HOST
localhost 找 PostgreSQL → ✅ 使用 Service Name postgres
3000:3000
$1、$2 參數化查詢GET /employees
POST /employees
今天終於把 Node.js、Express 和 PostgreSQL 真正串在一起。之前雖然 Node.js 已經可以查詢資料庫,但今天加入 API 後,整個專題的資料流程變得更完整。
前端不需要直接操作 PostgreSQL,而是先把 Request 傳給 Express,再由後端執行 SQL,最後把結果用 JSON 回傳。這也讓我更清楚前端、後端和資料庫各自負責的工作。
另外今天也學到參數化查詢,原本可能會很直覺地把變數直接放進 SQL 字串,但使用 $1、$2 的方式會更加安全。
目前已經可以透過 API 查詢與新增員工,接下來就可以把 PostgreSQL、Node.js 和整個 Docker Compose 環境整理在一起,完成一套可以快速建立的開發環境。