ویژگی تصویر

ساخت RESTful API در Node.js

  /  Node.js   /  ساخت RESTful API در Node.js
بنر تبلیغاتی الف
NodeJS - Node.js

RESTful API یکی از پراستفاده‌ترین الگوها برای ارتباط کلاینت و سرور است. در اکوسیستم Node.js، فریم‌ورک Express همراه با ابزارهایی مثل Mongoose (برای MongoDB)، بسته‌های اعتبارسنجی، و middlewareها باعث می‌شوند ساخت یک API امن، مقیاس‌پذیر و قابل تست ساده‌تر شود. در این مقاله قدم‌به‌قدم مفاهیم کلیدی، الگوهای طراحی و مثال‌های عملی را بررسی می‌کنیم.

ویژگی‌های مهم یک RESTful API خوب

  • ساختار منطقی و منابع مشخص (نقش URLها)
  • استفاده از متدهای HTTP مناسب (GET, POST, PUT/PATCH, DELETE)
  • حالت‌های پاسخ‌دهی استاندارد با HTTP Status Codes
  • اعتبارسنجی ورودی‌ها و مدیریت خطا
  • امنیت: احراز هویت، مجوزها، و جلوگیری از حملات رایج
  • مقیاس‌پذیری و قابلیت کشینگ/لاگینگ

نمونه ساختار پروژه

یک ساختار ساده اما موثر:

  • server.js — نقطه ورود
  • routes/ — تعریف مسیرها
  • controllers/ — منطق تجاری
  • models/ — اسکیمای دیتابیس
  • middleware/ — اعتبارسنجی، احراز هویت، خطایاب

نمونه پایه: server.js با Express

const express = require('express');
const mongoose = require('mongoose');
const cors = require('cors');
const helmet = require('helmet');
const routes = require('./routes');

const app = express();

app.use(helmet());
app.use(cors());
app.use(express.json());

app.use('/api', routes);

// Global error handler
app.use((err, req, res, next) => {
  console.error(err);
  res.status(err.status || 500).json({ error: err.message || 'Internal Server Error' });
});

const PORT = process.env.PORT || 3000;
mongoose.connect(process.env.MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true })
  .then(() => app.listen(PORT, () => console.log('Server running on port', PORT)))
  .catch(err => console.error('DB connection error', err));

این کد یک اپ ساده Express راه‌اندازی می‌کند، هدرهای امنیتی پایه را با helmet اضافه می‌کند، CORS فعال می‌سازد، و JSON ورودی را پارس می‌کند. سپس روت‌های API را روی مسیر /api قرار می‌دهد و یک error handler سراسری برای مدیریت خطاها ثبت می‌کند. همچنین اتصال به MongoDB قبل از گوش کردن به پورت انجام می‌شود.

مدل داده با Mongoose

const mongoose = require('mongoose');

const PostSchema = new mongoose.Schema({
  title: { type: String, required: true, trim: true },
  body: { type: String, required: true },
  author: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
  tags: [String],
  createdAt: { type: Date, default: Date.now }
});

module.exports = mongoose.model('Post', PostSchema);

این اسکیمای ساده یک مدل Post را تعریف می‌کند که برای CRUD پست‌ها در یک بلاگ مناسب است. نکاتی مثل trim، required و ارجاع به مدل User نشان‌دهنده روابط بین منابع هستند.

مسیرها و کنترلرها (CRUD)

const express = require('express');
const router = express.Router();
const Post = require('../models/Post');

// Create
router.post('/posts', async (req, res, next) => {
  try {
    const post = await Post.create(req.body);
    res.status(201).json(post);
  } catch (err) { next(err); }
});

// Read (list with pagination)
router.get('/posts', async (req, res, next) => {
  try {
    const page = Math.max(1, parseInt(req.query.page) || 1);
    const limit = Math.min(100, parseInt(req.query.limit) || 10);
    const posts = await Post.find()
      .skip((page - 1) * limit)
      .limit(limit)
      .sort({ createdAt: -1 });
    res.json(posts);
  } catch (err) { next(err); }
});

// Read (single)
router.get('/posts/:id', async (req, res, next) => {
  try {
    const post = await Post.findById(req.params.id);
    if (!post) return res.status(404).json({ error: 'Not found' });
    res.json(post);
  } catch (err) { next(err); }
});

// Update
router.put('/posts/:id', async (req, res, next) => {
  try {
    const post = await Post.findByIdAndUpdate(req.params.id, req.body, { new: true, runValidators: true });
    if (!post) return res.status(404).json({ error: 'Not found' });
    res.json(post);
  } catch (err) { next(err); }
});

// Delete
router.delete('/posts/:id', async (req, res, next) => {
  try {
    const post = await Post.findByIdAndDelete(req.params.id);
    if (!post) return res.status(404).json({ error: 'Not found' });
    res.status(204).end();
  } catch (err) { next(err); }
});

module.exports = router;

در این مثال، مسیرها به صورت RESTful تعریف شده‌اند: استفاده از متدهای HTTP برای عملیات CRUD، پیاده‌سازی صفحه‌بندی ساده و بازگرداندن کدهای وضعیت مناسب. هر خطا به middleware خطا فرستاده می‌شود تا مدیریت مرکزی شود.

الگو: async wrapper برای جلوگیری از تکرار try/catch

const asyncHandler = fn => (req, res, next) => Promise.resolve(fn(req, res, next)).catch(next);

router.get('/posts/:id', asyncHandler(async (req, res) => {
  const post = await Post.findById(req.params.id);
  if (!post) return res.status(404).json({ error: 'Not found' });
  res.json(post);
}));

تابع asyncHandler به صورت عمومی برای بسته‌بندی توابع async استفاده می‌شود تا نیاز به نوشتن try/catch در هر مسیر حذف شود و خطاها مستقیم به error handler ارسال شوند.

احراز هویت با JWT و middleware

const jwt = require('jsonwebtoken');

const auth = (req, res, next) => {
  const header = req.headers.authorization;
  if (!header) return res.status(401).json({ error: 'No token' });
  const token = header.split(' ')[1];
  try {
    const payload = jwt.verify(token, process.env.JWT_SECRET);
    req.user = payload;
    next();
  } catch (err) {
    res.status(401).json({ error: 'Invalid token' });
  }
};

module.exports = auth;

این middleware توکن را از هدر Authorization می‌خواند، آن را بررسی می‌کند و در صورت معتبر بودن، اطلاعات کاربر را در req.user قرار می‌دهد. سپس می‌توان از این middleware برای محافظت از روت‌های خصوصی استفاده کرد.

بهبودها، امنیت و بهینه‌سازی

  • اعتبارسنجی ورودی: از کتابخانه‌هایی مثل Joi یا express-validator استفاده کنید.
  • Rate Limiting: جلوگیری از حملات DDoS با express-rate-limit.
  • Logging و Monitoring: استفاده از winston یا سرویس‌های APM.
  • Caching: پاسخ‌های غیر داینامیک را با Redis کش کنید.
  • مهاجرت داده و ایندکس‌ها: برای کوئری‌های سنگین، ایندکس مناسب در MongoDB تعریف کنید.

جدول مرجع سریع متدها و کد وضعیت

HTTP Methodمعنی
GETخواندن داده
POSTایجاد منابع
PUT/PATCHبه‌روزرسانی
DELETEحذف
Status Codeمعنی
200OK
201Created
400Bad Request
401Unauthorized
404Not Found
500Internal Server Error

تست، مستندسازی و انتشار

  • تست واحد و انتها-به-انتها: از Jest و Supertest برای تست API استفاده کنید.
  • مستندسازی: OpenAPI (Swagger) برای توصیف و تولید مستندات تعاملی.
  • CI/CD: اجرای تست‌ها و استقرار خودکار با GitHub Actions یا GitLab CI.

جمع‌بندی و نکات مهم

ساخت RESTful API در Node.js ترکیبی از طراحی خوب، امنیت و عملیات صحیح است. با استفاده از ساختار ماژولار (routes/controllers/models)، مدیریت خطا مرکزی، و middlewareهای استاندارد می‌توانید APIهایی قابل نگهداری و مقیاس‌پذیر بسازید. توجه ویژه به اعتبارسنجی ورودی، احراز هویت، لاگینگ و تست اتوماتیک کیفیت سرویس شما را بالا می‌برد.

آیا این مطلب برای شما مفید بود ؟

خیر
بله
موضوعات شما در انجمن: