Workstation Logo
المنتجات
مختبرات الذكاء الاصطناعيوكلاء OpenAIوكلاء ClaudeGrok BotWorkstation CRM (WSL CRM)التسويقجميع المنتجات
حلول الذكاء الاصطناعي
محطات عمل الذكاء الاصطناعيAI SME Packagesذكاء اصطناعي خاصمجموعات GPUذكاء اصطناعي طرفيمختبر الذكاء الاصطناعي للمؤسساتالذكاء الاصطناعي حسب الصناعة
الخدمات
Platform ModernisationDigital EngineeringData Foundations & AIAutonomous Operationsاستشارات الذكاء الاصطناعيأتمتة DevOpsالأمن السيبرانيتطوير البرمجياتبناء الوكلاءإعداد MLOps
من نحن
الشركاءقصص العملاء
المقالات
الوثائق
WSL ProxyRing PromoterWSL VaultJobshoutSysOps 24/7
المدونة
اتصل بناLogin
Workstation

محطات عمل الذكاء الاصطناعي وبرمجيات الوكلاء المتعددة والبنية التحتية لوحدات GPU وحلول الوكلاء الأذكياء للشركات الحديثة.

اتصل بنا

حلول الذكاء الاصطناعي

محطات عمل الذكاء الاصطناعيAI SME Packagesذكاء اصطناعي خاصمجموعات GPUذكاء اصطناعي طرفيمختبر الذكاء الاصطناعي للمؤسساتالذكاء الاصطناعي حسب الصناعة

المنتجات

جميع المنتجاتWSL CRM و ERPالتسويقوكلاء OpenAIWSL ProxyRing PromoterWSL VaultJobshoutSysOps 24/7

الشركة

من نحنلماذا Workstationالشركاءقصص العملاءالأسعاراتصل

الموارد

المقالاتالتوثيقالمدونةبحثخريطة الموقع
مكتب المملكة المتحدة
77-79 Marlowes, Hemel Hempstead HP1 1LFالاتجاهات - اسلك المخرج 20 من الطريق M25 في لندن الخارجيةرقم الشركة: 11641870الاثنين - الجمعة: 9:00 ص - 6:00 م بتوقيت GMT
+44 7515 356 146
مكتب بلجيكا
Workstation SRL, Rue Vanderkindere 34, 1180 Uccle, BrusselsBE 0751.518.683الاثنين - الجمعة: 9:00 ص - 6:00 م بتوقيت CET
+32 492 45 67 46
مكتب الهند
#159 Sector 9, Pocket 1, DDA Flats, 110077 Dwarka, New Delhi
+91 98881 98841

© 2026 Workstation AI. جميع الحقوق محفوظة.

الخصوصيةملفات تعريف الارتباطشروط الخدمةخريطة الموقع الإلكتروني

Loading blog...

Home / Blog
WebFrontendReact

إنشاء أنظمة خلفية قوية باستخدام Node.js وMySQL

تصميم وتنفيذ APIs للواجهة الخلفية الآمنة والقابلة للتطوير باستخدام Node.js وExpress وMySQL

Balinder Walia27 مايو 202511 min read
تظل

Node.js وMySQL واحدة من المجموعات الأكثر موثوقية واختبارها في المعركة لبناء أنظمة الواجهة الخلفية. يوفر Node.js نموذج إدخال/إخراج غير محظور يحركه الحدث ويتعامل مع الطلبات المتزامنة بكفاءة، بينما يوفر MySQL تكامل البيانات الارتباطية التي تتطلبها تطبيقات الأعمال. إنهم يشكلون معًا أساسًا يدعم كل شيء بدءًا من أفضل الشركات الناشئة وحتى منصات المؤسسات التي تتعامل مع ملايين الطلبات يوميًا.

يتناول هذا الدليل كيفية إنشاء واجهة خلفية على مستوى الإنتاج API، ويغطي هيكل المشروع وتصميم قاعدة البيانات والمصادقة ومعالجة الأخطاء والنشر.

Express.js هيكل المشروع

Node.js + بنية الواجهة الخلفية السريعةطبقة البرمجيات الوسيطةالمصادقة (JWT)التحقق من الصحةحد المعدلCORSHelmetتسجيلالعميلالمتصفح / التطبيقAPIالبوابة/api/v1ExpressطرقGET/POST/PUT/DELوحدات التحكمالتعامل مع الطلبالخدماتمنطق الأعمالMySQLقواعد البيانات العلائقيةHTTPالطريقاتصل بـاتصل بـاستعلامتنسيق الاستجابة{ النجاح: صحيح، بيانات: [...]، ترقيم الصفحات: {...}}خطأ في معالجة خط الأنابيبApiErrorasyncHandlererrorHandlerاستجابات مركزية ومتسقة للأخطاء

هيكل المشروع المنظم جيدًا هو أساس الواجهة الخلفية القابلة للصيانة. افصل بين الاهتمامات بوضوح وقم بوضع اتفاقيات في وقت مبكر.

project-root/
  src/
    config/
      database.js
      environment.js
      logger.js
    middleware/
      auth.js
      errorHandler.js
      rateLimiter.js
      validator.js
    models/
      User.js
      Product.js
      Order.js
      index.js
    routes/
      auth.routes.js
      users.routes.js
      products.routes.js
      orders.routes.js
      index.js
    services/
      auth.service.js
      user.service.js
      product.service.js
      email.service.js
    utils/
      ApiError.js
      asyncHandler.js
      pagination.js
    app.js
    server.js
  migrations/
  seeders/
  tests/
  .env
  .env.example
  package.json

تقوم نقطة الإدخال بإعداد Express باستخدام البرامج الوسيطة الأساسية:

// src/app.js
const express = require('express');
const cors = require('cors');
const helmet = require('helmet');
const morgan = require('morgan');
const { errorHandler } = require('./middleware/errorHandler');
const routes = require('./routes');

const app = express();

// Security middleware
app.use(helmet());
app.use(cors({
  origin: process.env.ALLOWED_ORIGINS?.split(',') || 'http://localhost:3000',
  credentials: true,
}));

// Request parsing
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true }));

// Logging
app.use(morgan(process.env.NODE_ENV === 'production' ? 'combined' : 'dev'));

// Health check
app.get('/health', (req, res) => {
  res.json({ status: 'ok', timestamp: new Date().toISOString() });
});

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

// Error handling (must be last)
app.use(errorHandler);

module.exports = app;

RESTful API Design

صمم نقاط نهاية API الخاصة بك باتباع اصطلاحات REST. استخدم الأسماء للموارد، وطرق HTTP للإجراءات، وتنسيقات الاستجابة المتسقة.

// src/routes/products.routes.js
const router = require('express').Router();
const { authenticate, authorize } = require('../middleware/auth');
const { validate } = require('../middleware/validator');
const { createProductSchema, updateProductSchema } = require('../validators/product');
const productController = require('../controllers/product.controller');

router.get('/', productController.getAll);
router.get('/:id', productController.getById);
router.post('/',
  authenticate,
  authorize('admin'),
  validate(createProductSchema),
  productController.create
);
router.put('/:id',
  authenticate,
  authorize('admin'),
  validate(updateProductSchema),
  productController.update
);
router.delete('/:id',
  authenticate,
  authorize('admin'),
  productController.delete
);

module.exports = router;

يجب أن تكون وحدات التحكم رفيعة، مما يؤدي إلى تفويض منطق الأعمال إلى فئات الخدمة:

// src/controllers/product.controller.js
const productService = require('../services/product.service');
const { asyncHandler } = require('../utils/asyncHandler');

exports.getAll = asyncHandler(async (req, res) => {
  const { page = 1, limit = 20, sort = 'created_at', order = 'DESC', search } = req.query;

  const result = await productService.findAll({
    page: parseInt(page),
    limit: Math.min(parseInt(limit), 100),
    sort,
    order,
    search,
  });

  res.json({
    success: true,
    data: result.products,
    pagination: {
      page: result.page,
      limit: result.limit,
      total: result.total,
      totalPages: result.totalPages,
    },
  });
});

exports.create = asyncHandler(async (req, res) => {
  const product = await productService.create(req.body);
  res.status(201).json({
    success: true,
    data: product,
  });
});

MySQL تجمع الاتصال مع mysql2

MySQL بنية تجمع الاتصالالتطبيقالطلبات المتزامنةطلب موضوع 1طلب الموضوع 2طلب الموضوع 3طلب الموضوع 4...طلب الموضوع Nتجمع الاتصال (mysql2)نشطخاملاتصال1 - اتصال2 نشط - اتصال3 - اتصالنشطاتصال4 - اتصالنشط 5 - خامل اتصالالحد: 10 | waitForConnections: صحيحenableKeepAlive: صحيح | حد الانتظار: 0MySQLخادم قاعدة البياناتمخزن البياناتفهارسمحرك InnoDBيعيد استخدام الاتصالات، مع تجنب الحمل الزائد لإنشاء اتصالات جديدة لكل طلب

يعد تجميع الاتصالات أمرًا بالغ الأهمية للأداء. توفر حزمةmysql2API المستندة إلى الوعد مع البيانات المعدة وتجميع الاتصال خارج الصندوق.

// src/config/database.js
const mysql = require('mysql2/promise');
const logger = require('./logger');

const pool = mysql.createPool({
  host: process.env.DB_HOST || 'localhost',
  port: parseInt(process.env.DB_PORT) || 3306,
  user: process.env.DB_USER,
  password: process.env.DB_PASSWORD,
  database: process.env.DB_NAME,
  waitForConnections: true,
  connectionLimit: parseInt(process.env.DB_POOL_SIZE) || 10,
  queueLimit: 0,
  enableKeepAlive: true,
  keepAliveInitialDelay: 30000,
  timezone: '+00:00',
  typeCast: function (field, next) {
    if (field.type === 'TINY' && field.length === 1) {
      return field.string() === '1';
    }
    return next();
  },
});

// Test connection on startup
pool.getConnection()
  .then(conn => {
    logger.info('MySQL connected successfully');
    conn.release();
  })
  .catch(err => {
    logger.error('MySQL connection failed:', err.message);
    process.exit(1);
  });

module.exports = pool;

استخدم دائمًا الاستعلامات ذات المعلمات لمنع حقن SQL:

// NEVER do this
const query = `SELECT * FROM users WHERE email = '${email}'`;

// ALWAYS use parameterized queries
const [rows] = await pool.execute(
  'SELECT id, email, first_name, last_name FROM users WHERE email = ?',
  [email]
);

Sequelize ORM

بالنسبة للتطبيقات ذات علاقات البيانات المعقدة، يوفر Sequelize ORM كامل الميزات مع تعريفات النماذج والارتباطات والترحيلات وبناء الاستعلام.

// src/models/Product.js
const { DataTypes } = require('sequelize');
const sequelize = require('../config/sequelize');

const Product = sequelize.define('Product', {
  id: {
    type: DataTypes.UUID,
    defaultValue: DataTypes.UUIDV4,
    primaryKey: true,
  },
  name: {
    type: DataTypes.STRING(255),
    allowNull: false,
    validate: {
      notEmpty: true,
      len: [2, 255],
    },
  },
  description: {
    type: DataTypes.TEXT,
    allowNull: true,
  },
  price: {
    type: DataTypes.DECIMAL(10, 2),
    allowNull: false,
    validate: {
      min: 0,
    },
  },
  sku: {
    type: DataTypes.STRING(100),
    unique: true,
    allowNull: false,
  },
  stock_quantity: {
    type: DataTypes.INTEGER,
    defaultValue: 0,
    validate: {
      min: 0,
    },
  },
  is_active: {
    type: DataTypes.BOOLEAN,
    defaultValue: true,
  },
}, {
  tableName: 'products',
  timestamps: true,
  underscored: true,
  paranoid: true, // Soft deletes
  indexes: [
    { fields: ['sku'], unique: true },
    { fields: ['is_active'] },
    { fields: ['price'] },
    { fields: ['created_at'] },
  ],
});

// Associations
Product.associate = (models) => {
  Product.belongsTo(models.Category, { foreignKey: 'category_id' });
  Product.hasMany(models.OrderItem, { foreignKey: 'product_id' });
  Product.belongsToMany(models.Tag, { through: 'product_tags' });
};

module.exports = Product;

المصادقة باستخدام JWT

تنفيذ مصادقة عديمة الحالة باستخدام رموز الويب JSON. استخدم رموز الوصول لطلبات API ورموز التحديث لإدارة الجلسة.

// src/services/auth.service.js
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
const { User } = require('../models');
const ApiError = require('../utils/ApiError');

const SALT_ROUNDS = 12;
const ACCESS_TOKEN_EXPIRY = '15m';
const REFRESH_TOKEN_EXPIRY = '7d';

exports.register = async ({ email, password, firstName, lastName }) => {
  const existingUser = await User.findOne({ where: { email } });
  if (existingUser) {
    throw new ApiError(409, 'Email already registered');
  }

  const hashedPassword = await bcrypt.hash(password, SALT_ROUNDS);
  const user = await User.create({
    email,
    password: hashedPassword,
    first_name: firstName,
    last_name: lastName,
  });

  const tokens = generateTokens(user);
  return { user: sanitizeUser(user), ...tokens };
};

exports.login = async ({ email, password }) => {
  const user = await User.findOne({ where: { email } });
  if (!user || !(await bcrypt.compare(password, user.password))) {
    throw new ApiError(401, 'Invalid email or password');
  }

  const tokens = generateTokens(user);
  return { user: sanitizeUser(user), ...tokens };
};

function generateTokens(user) {
  const accessToken = jwt.sign(
    { userId: user.id, email: user.email, role: user.role },
    process.env.JWT_SECRET,
    { expiresIn: ACCESS_TOKEN_EXPIRY }
  );

  const refreshToken = jwt.sign(
    { userId: user.id, tokenType: 'refresh' },
    process.env.JWT_REFRESH_SECRET,
    { expiresIn: REFRESH_TOKEN_EXPIRY }
  );

  return { accessToken, refreshToken };
}

function sanitizeUser(user) {
  const { password, ...userData } = user.toJSON();
  return userData;
}

تتحقق البرامج الوسيطة للمصادقة من الرموز المميزة على المسارات المحمية:

// src/middleware/auth.js
const jwt = require('jsonwebtoken');
const ApiError = require('../utils/ApiError');

exports.authenticate = (req, res, next) => {
  const authHeader = req.headers.authorization;
  if (!authHeader?.startsWith('Bearer ')) {
    throw new ApiError(401, 'Access token required');
  }

  const token = authHeader.split(' ')[1];
  try {
    const decoded = jwt.verify(token, process.env.JWT_SECRET);
    req.user = decoded;
    next();
  } catch (error) {
    if (error.name === 'TokenExpiredError') {
      throw new ApiError(401, 'Access token expired');
    }
    throw new ApiError(401, 'Invalid access token');
  }
};

exports.authorize = (...roles) => {
  return (req, res, next) => {
    if (!roles.includes(req.user.role)) {
      throw new ApiError(403, 'Insufficient permissions');
    }
    next();
  };
};

التحقق من صحة الإدخال باستخدام Joi

التحقق من صحة جميع البيانات الواردة قبل أن تصل إلى منطق عملك. يوفر Joi مكتبة تحقق قوية قائمة على المخطط.

// src/validators/product.js
const Joi = require('joi');

exports.createProductSchema = Joi.object({
  name: Joi.string().min(2).max(255).required(),
  description: Joi.string().max(5000).optional(),
  price: Joi.number().positive().precision(2).required(),
  sku: Joi.string().alphanum().max(100).required(),
  stock_quantity: Joi.number().integer().min(0).default(0),
  category_id: Joi.string().uuid().required(),
  tags: Joi.array().items(Joi.string().uuid()).optional(),
  is_active: Joi.boolean().default(true),
});

exports.updateProductSchema = Joi.object({
  name: Joi.string().min(2).max(255),
  description: Joi.string().max(5000).allow(null),
  price: Joi.number().positive().precision(2),
  stock_quantity: Joi.number().integer().min(0),
  category_id: Joi.string().uuid(),
  is_active: Joi.boolean(),
}).min(1);

// src/middleware/validator.js
exports.validate = (schema) => {
  return (req, res, next) => {
    const { error, value } = schema.validate(req.body, {
      abortEarly: false,
      stripUnknown: true,
    });

    if (error) {
      const errors = error.details.map(detail => ({
        field: detail.path.join('.'),
        message: detail.message,
      }));
      return res.status(400).json({
        success: false,
        message: 'Validation failed',
        errors,
      });
    }

    req.body = value;
    next();
  };
};

معالجة الأخطاء للبرامج الوسيطة

تضمن معالجة الأخطاء المركزية استجابات متسقة للأخطاء وتمنع تسرب المعلومات الحساسة إلى العملاء.

// src/utils/ApiError.js
class ApiError extends Error {
  constructor(statusCode, message, errors = []) {
    super(message);
    this.statusCode = statusCode;
    this.errors = errors;
    this.isOperational = true;
    Error.captureStackTrace(this, this.constructor);
  }
}

module.exports = ApiError;

// src/utils/asyncHandler.js
exports.asyncHandler = (fn) => (req, res, next) => {
  Promise.resolve(fn(req, res, next)).catch(next);
};

// src/middleware/errorHandler.js
const logger = require('../config/logger');

exports.errorHandler = (err, req, res, next) => {
  let statusCode = err.statusCode || 500;
  let message = err.message || 'Internal Server Error';

  // Sequelize validation errors
  if (err.name === 'SequelizeValidationError') {
    statusCode = 400;
    message = 'Validation error';
  }

  // Sequelize unique constraint
  if (err.name === 'SequelizeUniqueConstraintError') {
    statusCode = 409;
    message = 'Resource already exists';
  }

  // Log server errors
  if (statusCode >= 500) {
    logger.error({
      message: err.message,
      stack: err.stack,
      url: req.originalUrl,
      method: req.method,
      ip: req.ip,
    });
  }

  res.status(statusCode).json({
    success: false,
    message,
    ...(process.env.NODE_ENV === 'development' && { stack: err.stack }),
    ...(err.errors?.length && { errors: err.errors }),
  });
};

تحسين الاستعلام وفهرسته

تعد استعلامات قاعدة البيانات الفعالة أمرًا بالغ الأهمية لأداء الواجهة الخلفية. اتبع هذه الاستراتيجيات لإبقاء استعلامات MySQL الخاصة بك سريعة.

  • استخدم الفهارس على الأعمدة التي يتم الاستعلام عنها بشكل متكرر- أضف فهارس على الأعمدة المستخدمة في عبارات WHERE وشروط JOIN وعبارات ORDER BY. يجب أن تتبع الفهارس المركبة قاعدة البادئة الموجودة في أقصى اليسار.
  • تجنب التحديد *- حدد دائمًا الأعمدة التي تحتاجها. وهذا يقلل من نقل البيانات ويسمح لـ MySQL باستخدام فهارس التغطية.
  • استخدم EXPLAIN لتحليل الاستعلامات- قم بتشغيلEXPLAINقبل استعلاماتك لفهم خطة التنفيذ. ابحث عن عمليات فحص الجدول الكامل وعمليات فرز الملفات والجداول المؤقتة.
  • تحسين ترقيم الصفحات- بالنسبة لمجموعات البيانات الكبيرة، استخدم ترقيم الصفحات المستند إلى المؤشر (ترقيم الصفحات لمجموعة المفاتيح) بدلاً من OFFSET، الذي يصبح بطيئًا عند ارتفاع أرقام الصفحات.
// Inefficient OFFSET pagination
const [rows] = await pool.execute(
  'SELECT * FROM products ORDER BY created_at DESC LIMIT ? OFFSET ?',
  [limit, (page - 1) * limit]
);

// Efficient cursor-based pagination
const [rows] = await pool.execute(
  `SELECT id, name, price, created_at FROM products
   WHERE created_at < ?
   ORDER BY created_at DESC
   LIMIT ?`,
  [cursor, limit]
);

عمليات ترحيل قاعدة البيانات

لا تقم مطلقًا بتعديل قواعد بيانات الإنتاج يدويًا. استخدم Sequelize عمليات الترحيل لتغييرات المخطط التي يتم التحكم فيها بالإصدار.

// migrations/20250101000000-create-products-table.js
module.exports = {
  up: async (queryInterface, Sequelize) => {
    await queryInterface.createTable('products', {
      id: {
        type: Sequelize.UUID,
        defaultValue: Sequelize.UUIDV4,
        primaryKey: true,
      },
      name: {
        type: Sequelize.STRING(255),
        allowNull: false,
      },
      price: {
        type: Sequelize.DECIMAL(10, 2),
        allowNull: false,
      },
      sku: {
        type: Sequelize.STRING(100),
        unique: true,
        allowNull: false,
      },
      category_id: {
        type: Sequelize.UUID,
        references: {
          model: 'categories',
          key: 'id',
        },
        onUpdate: 'CASCADE',
        onDelete: 'SET NULL',
      },
      created_at: {
        type: Sequelize.DATE,
        defaultValue: Sequelize.literal('CURRENT_TIMESTAMP'),
      },
      updated_at: {
        type: Sequelize.DATE,
        defaultValue: Sequelize.literal('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'),
      },
    });

    await queryInterface.addIndex('products', ['sku']);
    await queryInterface.addIndex('products', ['category_id']);
    await queryInterface.addIndex('products', ['created_at']);
  },

  down: async (queryInterface) => {
    await queryInterface.dropTable('products');
  },
};

تحديد المعدل

قم بحماية جهاز API الخاص بك من سوء الاستخدام من خلال تحديد المعدل. استخدمexpress-rate-limitمع متجر Redis لعمليات النشر الموزعة.

// src/middleware/rateLimiter.js
const rateLimit = require('express-rate-limit');
const RedisStore = require('rate-limit-redis');
const redis = require('../config/redis');

exports.apiLimiter = rateLimit({
  store: new RedisStore({ sendCommand: (...args) => redis.call(...args) }),
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 100,
  message: {
    success: false,
    message: 'Too many requests, please try again later',
  },
  standardHeaders: true,
  legacyHeaders: false,
});

exports.authLimiter = rateLimit({
  store: new RedisStore({ sendCommand: (...args) => redis.call(...args) }),
  windowMs: 15 * 60 * 1000,
  max: 5,
  message: {
    success: false,
    message: 'Too many login attempts, please try again later',
  },
  skipSuccessfulRequests: true,
});

التسجيل باستخدام Winston

تحتاج تطبيقات الإنتاج إلى تسجيل منظم باستخدام عمليات نقل ومستويات تسجيل متعددة.

// src/config/logger.js
const winston = require('winston');

const logger = winston.createLogger({
  level: process.env.LOG_LEVEL || 'info',
  format: winston.format.combine(
    winston.format.timestamp(),
    winston.format.errors({ stack: true }),
    winston.format.json()
  ),
  defaultMeta: { service: 'api-server' },
  transports: [
    new winston.transports.File({
      filename: 'logs/error.log',
      level: 'error',
      maxsize: 5242880, // 5MB
      maxFiles: 5,
    }),
    new winston.transports.File({
      filename: 'logs/combined.log',
      maxsize: 5242880,
      maxFiles: 10,
    }),
  ],
});

if (process.env.NODE_ENV !== 'production') {
  logger.add(new winston.transports.Console({
    format: winston.format.combine(
      winston.format.colorize(),
      winston.format.simple()
    ),
  }));
}

module.exports = logger;

Docker النشر

قم بتخزين تطبيقك من أجل عمليات نشر متسقة عبر البيئات.

# Dockerfile
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

FROM node:20-alpine
WORKDIR /app
RUN addgroup -g 1001 -S appgroup && \
    adduser -S appuser -u 1001 -G appgroup
COPY --from=builder /app/node_modules ./node_modules
COPY src/ ./src/
COPY migrations/ ./migrations/
COPY package.json ./
USER appuser
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=3s \
  CMD wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1
CMD ["node", "src/server.js"]
# docker-compose.yml
version: '3.8'
services:
  api:
    build: .
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - DB_HOST=mysql
      - DB_USER=app_user
      - DB_PASSWORD_FILE=/run/secrets/db_password
      - DB_NAME=myapp
    depends_on:
      mysql:
        condition: service_healthy
    restart: unless-stopped

  mysql:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db_root_password
      MYSQL_DATABASE: myapp
      MYSQL_USER: app_user
      MYSQL_PASSWORD_FILE: /run/secrets/db_password
    volumes:
      - mysql_data:/var/lib/mysql
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  mysql_data:

الاستنتاج

يتطلب إنشاء واجهة خلفية قوية لـ Node.js وMySQL الاهتمام بالهندسة المعمارية والأمن والأداء والمخاوف التشغيلية. من خلال إنشاء بنية مشروع نظيفة، وتنفيذ المصادقة والتحقق المناسبين، وتحسين استعلامات قاعدة البيانات، ووضع النشر في حاوية، يمكنك إنشاء واجهة خلفية آمنة وفعالة وقابلة للصيانة. ابدأ بالأساسيات الموضحة في هذا الدليل، وقم بقياس أداء التطبيق الخاص بك في ظل التحميل الواقعي، ثم قم بالتكرار على الاختناقات التي تكتشفها. لقد تم إثبات الأنماط المعروضة هنا عبر الآلاف من تطبيقات الإنتاج وستكون بمثابة أساس متين لأنظمة الواجهة الخلفية لديك.