[Series Thực Chiến E-commerce] Bài 2: "Thông mạch" database với MongoDB & Viết API Đăng ký user đầu tay
Chào lại anh em!
Ở Bài 1, chúng ta đã dựng thành công cái khung nhà (Node.js Server) rồi. Nhưng một hệ thống mà không có database thì cũng chỉ như cái vỏ rỗng không có trí nhớ. Bài hôm nay, chúng ta sẽ bắt tay vào làm phần cốt lõi nhất: Kết nối cơ sở dữ liệu MongoDB và tạo tính năng Đăng ký người dùng (Register).
Mình sẽ hướng dẫn anh em chia cấu trúc file cực kỳ rành mạch. Tin mình đi, dự án càng to, anh em sẽ càng thấy biết ơn cái cấu trúc này! Bắt đầu nhé!
1. Kết nối MongoDB: Tạo nhịp đập cho hệ thống
Anh em có thể cài MongoDB chạy dưới local (localhost:27017), hoặc dùng MongoDB Atlas (Cloud) đều được. Khai báo ngay vào file .env:
PORT=5000
MONGODB_URI=mongodb://localhost:27017/ecommerce
Tiếp theo, mở file config/dbConnect.js. Đây là nơi chứa logic kết nối cơ sở dữ liệu.
const { default: mongoose } = require('mongoose');
const dbConnect = async () => {
try {
const conn = await mongoose.connect(process.env.MONGODB_URI);
// readyState === 1 nghĩa là đã kết nối thành công
if (conn.connection.readyState === 1) {
console.log('✅ Kết nối Database thành công!');
} else {
console.log('⏳ Đang kết nối Database...');
}
} catch (error) {
console.log('❌ Kết nối Database thất bại!');
throw new Error(error);
}
};
module.exports = dbConnect;
Kinh nghiệm thực chiến: Luôn dùng try...catch khi kết nối DB và in log rõ ràng. Lúc server sập hoặc đổi môi trường, nhìn log là biết ngay do tạch DB hay do code lỗi.
2. Định nghĩa khuôn mẫu: Tạo User Model
Bản thân MongoDB là NoSQL, thích nhét gì vào cũng được (schema-less). Nhưng làm dự án thực tế mà thả rông data như vậy thì toang sớm. Mình sẽ dùng Mongoose để tạo ra một cái "khuôn đúc" nghiêm ngặt cho User.
Anh em tạo file models/user.js:
const mongoose = require('mongoose');
var userSchema = new mongoose.Schema(
{
firstname: { type: String, required: true, index: true },
lastname: { type: String, required: true },
email: { type: String, required: true, unique: true },
mobile: { type: String, required: true, unique: true },
password: { type: String, required: true },
role: { type: String, default: 'user' },
cart: { type: Array, default: [] },
address: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Address' }],
wishlist: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Product' }],
isBlocked: { type: Boolean, default: false },
refreshToken: { type: String },
passwordChangeAt: { type: String },
passwordResetToken: { type: String },
passwordResetExpires: { type: String },
},
{
timestamps: true, // Tự động sinh ra 2 trường createdAt và updatedAt
}
);
module.exports = mongoose.model('User', userSchema);
Điểm nhấn ở đây:
- unique: true cho email và mobile: DB sẽ tự chặn nếu có thằng nào đó cố tình đăng ký trùng email.
- index: true: Giúp tốc độ tìm kiếm user theo firstname sau này nhanh hơn hẳn.
- Các trường liên quan đến order, product được tham chiếu (ref) chờ sẵn để móc nối ở các bài sau.
3. Controller: Não bộ xử lý logic đăng ký
Bây giờ là lúc viết logic để nhét data từ client gửi lên vào DB. Mở file controllers/user.js:
const User = require('../models/user');
const asyncHandler = require('express-async-handler');
const register = asyncHandler(async (req, res) => {
const { email, password, firstname, lastname, mobile } = req.body;
// Validate sơ bộ: Trống một trong các trường này là đuổi về luôn
if (!email || !password || !lastname || !firstname || !mobile) {
return res.status(400).json({
success: false,
message: 'Vui lòng nhập đầy đủ các trường yêu cầu!',
});
}
// Quăng data vào DB
const response = await User.create(req.body);
return res.status(200).json({
success: response ? true : false,
response,
});
});
module.exports = { register };
Anh em thấy gói express-async-handler thần thánh chưa? Code rất clean, không cần bọc try...catch lằng nhằng. Nếu lúc User.create xảy ra lỗi (ví dụ trùng email), handler này sẽ tự động tóm lấy lỗi và đẩy ra ngoài (mình sẽ chỉ cách handle cái lỗi này đẹp mắt ở bài sau).
4. Chia luồng giao thông: Setup Router
Không nên nhét mọi route vào server.js, chúng ta sẽ phân luồng. Đầu tiên là tuyến đường dành riêng cho User (routers/user.js):
const router = require('express').Router();
const ctrls = require('../controllers/user');
// Endpoint: POST /api/user/register
router.post('/register', ctrls.register);
module.exports = router;
Tiếp theo là Trạm điều phối tổng (routers/index.js):
const userRouter = require('./user');
const initRouter = (app) => {
app.use('/api/user', userRouter); // Mọi request bắt đầu bằng /api/user sẽ chui vào đây
};
module.exports = initRouter;
5. Lắp ráp mảnh ghép cuối cùng vào server.js
Cuối cùng, quay lại file gốc server.js và nối mọi thứ lại với nhau:
const express = require('express');
const dotenv = require('dotenv');
const connectDB = require('./config/dbConnect');
const initRouter = require('./routers');
dotenv.config();
const app = express();
// 1. Gọi hàm kết nối Database
connectDB();
// 2. Middleware đọc hiểu JSON
app.use(express.json());
// 3. Khởi tạo toàn bộ Routes
initRouter(app);
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => {
console.log(`🚀 Server is running on port ${PORT}`);
});
Boom 💥! Xong rồi đó anh em. Mở Postman lên, bắn một request POST kèm JSON body vào http://localhost:5000/api/user/register là sẽ thấy user được lưu thẳng vào MongoDB
Lời kết Bài này chúng ta đã làm được một việc vĩ đại là kết nối thành công ứng dụng với cơ sở dữ liệu và lưu trữ được thông tin.
Ở bài tiếp theo, chúng ta sẽ bắt đầu Validation & Hash Password nhé. Anh em có góp ý hay gặp lỗi gì cứ ném vào phần comment, mình sẽ hỗ trợ. Hẹn gặp lại anh em ở Bài 3!
All rights reserved