ساخت پروژه چندلایه (MVC) در Node.js
معماری چندلایه یا MVC (Model-View-Controller) باعث جداسازی وظایف، تستپذیری و نگهداری آسانتر برنامههای وب میشود. در اکوسیستم Node.js که انعطاف و تنوع زیادی در انتخاب ابزارها وجود دارد، استفاده از الگوی MVC کمک میکند تا کد منظم، قابل فهم و قابل گسترش بماند. در این مقاله به صورت عملی ساخت یک پروژه چندلایه در Node.js با Express و Mongoose (برای MongoDB) را بررسی میکنیم و نکات حرفهای و بهینهسازیها را نیز مطرح میکنیم.
مزایا و موارد کاربرد
- تفکیک مسئولیتها و کاهش وابستگیها
- تسهیل تست واحد و یکپارچه
- مناسب برای برنامههای CRUD، APIهای RESTful و پروژههای با رشد سریع
ساختار پیشنهادی پوشهها
| پوشه/فایل | وظیفه |
|---|---|
| src/ | کد منبع پروژه |
| src/controllers/ | لایه Controller — دریافت درخواستها و هماهنگی سرویسها |
| src/models/ | لایه Model — اسکیمای داده و منطق مرتبط با دیتابیس |
| src/services/ | Business Logic — عملیات پیچیده و تعامل با مدلها |
| src/routes/ | تعریف مسیرها و middlewareها |
| src/middlewares/ | Middlewareهای عمومی مانند احراز هویت و لاگینگ |
| src/utils/ | توابع کمکی و خطایابی |
نمونه ساده: راهاندازی اولیه با Express
// src/app.js
const express = require('express');
const mongoose = require('mongoose');
const routes = require('./routes');
const app = express();
app.use(express.json());
app.use('/api', routes);
mongoose.connect(process.env.MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true })
.then(() => console.log('Mongo connected'))
.catch(err => console.error(err));
module.exports = app;این فایل اصلی برنامه است: ایجاد اپ اکسپرس، فعالسازی پارس JSON، متصل کردن router کلی و اتصال به MongoDB با Mongoose. جدا نگه داشتن اتصال دیتابیس و پیکربندیها به تمیز ماندن پروژه کمک میکند.
نمونه مدل با Mongoose
// src/models/User.js
const mongoose = require('mongoose');
const userSchema = new mongoose.Schema({
name: { type: String, required: true, trim: true },
email: { type: String, required: true, unique: true },
passwordHash: { type: String, required: true },
createdAt: { type: Date, default: Date.now }
});
module.exports = mongoose.model('User', userSchema);در این بخش اسکیمای کاربر تعریف شده است. Model مسئول تعامل مستقیم با دیتابیس است و تمام قواعد ساختاری (required، unique و غیره) در اینجا قرار میگیرد.
نمونه Controller و Service
// src/services/userService.js
const User = require('../models/User');
const bcrypt = require('bcrypt');
async function createUser({ name, email, password }) {
const exists = await User.findOne({ email });
if (exists) throw new Error('Email already in use');
const passwordHash = await bcrypt.hash(password, 10);
const user = new User({ name, email, passwordHash });
return user.save();
}
module.exports = { createUser };
// src/controllers/userController.js
const userService = require('../services/userService');
async function register(req, res, next) {
try {
const user = await userService.createUser(req.body);
res.status(201).json({ id: user._id, name: user.name, email: user.email });
} catch (err) {
next(err);
}
}
module.exports = { register };در این مثال، service مسئول منطق کسبوکار (مثل هش کردن رمز و بررسی وجود ایمیل) است و controller فقط دریافت درخواست و ارسال پاسخ را انجام میدهد. این جداسازی امکان تست مستقل و استفاده مجدد را میدهد.
تعریف مسیرها (Routes)
// src/routes/index.js
const express = require('express');
const router = express.Router();
const userController = require('../controllers/userController');
router.post('/users', userController.register);
module.exports = router;فایل روتر مسیرهای مربوط به منابع را به کنترلرها متصل میکند. در پروژههای بزرگتر میتوانید هر منبع را در فایل جداگانهای داشته باشید و از versioning برای API استفاده کنید (/api/v1/…).
مدیریت خطا و Middleware
یک middleware مرکزی برای هندل خطاها تعریف کنید تا پاسخهای یکنواخت و لاگ مناسب داشته باشید. همچنین از middlewareهای اعتبارسنجی (مثلاً Joi یا express-validator) برای اعتبارسنجی درخواستها استفاده کنید.
تست و CI/CD
- برای تست واحد از Jest یا Mocha استفاده کنید و سرویسها و کنترلرها را جداگانه تست کنید.
- در CI، پیش از دیپلوی، تستها و lint را اجرا کنید و از environment variables امن استفاده کنید.
بهینهسازی و نکات حرفهای
- از Dependency Injection و مدیریت کانتینر (مانند Awilix) برای کاهش coupling استفاده کنید.
- لاگینگ ساختیافته (پام/PM2/Logstash) و مانیتورینگ برای production ضروری است.
- برای عملکرد بهتر، استراتژیهای caching و pagination را از ابتدا طراحی کنید.
- استفاده از تراکنشها و کنترل همزمانی (برای دیتابیسهایی که پشتیبانی میکنند) در عملیات حساس توصیه میشود.
مثال کاملتر: اعتبارسنجی درخواست با express-validator
// src/middlewares/validators.js
const { body, validationResult } = require('express-validator');
const registerValidation = [
body('name').isLength({ min: 2 }),
body('email').isEmail(),
body('password').isLength({ min: 6 }),
(req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) return res.status(400).json({ errors: errors.array() });
next();
}
];
module.exports = { registerValidation };
// استفاده در روتر
// router.post('/users', registerValidation, userController.register);در این کد از ابزار express-validator برای اعتبارسنجی بدنه درخواست استفاده میکنیم. در صورت بروز خطا یک پاسخ 400 با جزئیات ارسال میشود. این کار جلوی ورود دادههای ناصحیح به لایههای پایینتر را میگیرد.
جمعبندی و بهترین روشها
ساخت پروژه چندلایه در Node.js باعث بهبود نگهداری، خوانایی و توسعه تیمی میشود. نکات کلیدی:
- هر لایه یک مسئولیت مشخص داشته باشد (Controller: ورودی/خروجی، Service: منطق، Model: دیتابیس)
- از middlewareها برای cross-cutting concerns استفاده کنید (اعتبارسنجی، لاگ، خطا)
- تستهای واحد و یکپارچه را از ابتدا لحاظ کنید
- پیکربندی و اسرار (env) را خارج از کد نگه دارید و در CI/CD امن کنید
با رعایت این الگوها میتوانید برنامههای مقیاسپذیر و قابل اطمینان با Node.js بسازید. شروع ساده و افزودن لایهها و الگوهای پیچیدهتر (مانند CQRS یا Event-driven) زمانی مناسب است که نیازهای پروژه افزایش یابد.
آیا این مطلب برای شما مفید بود ؟




