今天是鐵人賽 Day15,目標是完成會員註冊 API,加入密碼加密功能(bcrypt),可透過 Postman 測試註冊、查詢與刪除會員,並新增密碼長度驗證(至少 6 個字元)。
1️⃣ 建立 User Schema
在 backend/models/User.js 中建立會員資料結構,欄位包含:
username:帳號,必填且唯一
email:信箱,必填且唯一
password:加密後密碼
role:會員角色,預設 "user"
createdAt:建立時間,預設為當前時間
同時加入 trim 與 lowercase 設定,保持資料格式一致
const mongoose = require('mongoose');
const userSchema = new mongoose.Schema({
username: { type: String, required: true, unique: true, trim: true },
email: { type: String, required: true, unique: true, lowercase: true, trim: true },
password: { type: String, required: true },
role: { type: String, enum: ["user", "admin"], default: "user" },
createdAt: { type: Date, default: Date.now }
});
module.exports = mongoose.model('User', userSchema);
2️⃣ 註冊會員 API(密碼加密 bcrypt)
在 backend/routes/userRoutes.js 中建立 /register POST API
功能:
檢查必填欄位
密碼長度至少 6 個字元
檢查帳號或信箱是否已存在
密碼加密後存入 MongoDB
回傳會員必要資訊(不含密碼)
router.post("/register", async (req, res) => {
try {
let { username, email, password } = req.body;
if (!username || !email || !password) {
return res.status(400).json({ message: "請填寫完整資料" });
}
if (password.length < 6) {
return res.status(400).json({ message: "密碼至少需要 6 個字元" });
}
username = username.trim();
email = email.trim().toLowerCase();
const existingUser = await User.findOne({ $or: [{ username }, { email }] });
if (existingUser) {
return res.status(400).json({ message: "帳號或信箱已被註冊" });
}
const hashedPassword = await bcrypt.hash(password, 10);
const newUser = new User({ username, email, password: hashedPassword });
await newUser.save();
res.status(201).json({
message: "註冊成功",
user: { username: newUser.username, email: newUser.email, role: newUser.role }
});
} catch (err) {
if (err.code === 11000) {
return res.status(400).json({ message: "帳號或信箱已被註冊(重複鍵值)" });
}
console.error("❌ 註冊失敗:", err);
res.status(500).json({ message: "伺服器錯誤" });
}
});
3️⃣ 會員資料查詢 API
GET /api/users:取得所有會員(不含密碼)
GET /api/users/:id:取得單一會員資料(不含密碼)
router.get("/", async (req, res) => {
const users = await User.find({}, "-password");
res.json(users);
});
router.get("/:id", async (req, res) => {
const user = await User.findById(req.params.id, "-password");
if (!user) return res.status(404).json({ message: "找不到會員" });
res.json(user);
});
4️⃣ 刪除會員 API
DELETE /api/users/:id:依會員 ID 刪除會員
router.delete("/:id", async (req, res) => {
const user = await User.findByIdAndDelete(req.params.id);
if (!user) return res.status(404).json({ message: "找不到會員" });
res.json({ message: "會員已刪除", user: { username: user.username, email: user.email } });
});
5️⃣ 後端測試流程(Postman)
POST /api/users/register → 註冊會員
GET /api/users → 取得會員列表
GET /api/users/:id → 取得單一會員
DELETE /api/users/:id → 刪除會員
密碼不會回傳前端,資料安全
密碼長度驗證生效
🐛 遇到的問題與解決
bcrypt 模組未安裝 → npm install bcryptjs
密碼少於 6 個字元 → 新增驗證
查詢或刪除會員 → 需注意 MongoDB _id 是否正確
💡 Day15 收穫