البرمجة مبتدئ 12 دقيقة

كيفية بناء واجهة REST API باستخدام Node.js و Express

لا يزال Express أكثر إطارات Node.js الويب انتشارًا. هو بسيط بتصميمه — يمنحك التوجيه والـ middleware وخادم HTTP. كل شيء آخر (التحقق، المصادقة، قاعدة البيانات) تضيفه بنفسك، مما يعني أنك تفهم تمامًا ما يوجد في مشروعك.

يبني هذا الدليل REST API عاملًا لمورد /api/users: عرض القائمة، قراءة سجل، إنشاء، تحديث، حذف. نبدأ من الصفر، ونُهيكل الكود عبر مجلدات routes/ وcontrollers/، ونتناول أدوات التطوير التي تجعل التكرار سريعًا. طبقة البيانات تستخدم مصفوفة في الذاكرة للوضوح — استبدالها بقاعدة بيانات حقيقية هو الخطوة الوحيدة التي تتغير عند الانتقال للإنتاج.

الخطوات

  1. 1

    أنشئ المشروع

    أنشئ مجلدًا جديدًا، هيّئ package.json، وثبّت Express. ثبّت nodemon كتبعية تطوير لإعادة التشغيل التلقائي خلال التطوير. ثبّت أيضًا dotenv لإدارة متغيرات البيئة منذ البداية.

    bash
    mkdir my-api && cd my-api
    npm init -y
    npm install express dotenv
    npm install --save-dev nodemon
    
    # سنضيف scripts إلى package.json في الخطوة التالية
  2. 2

    اضبط scripts في package.json

    أضف scripts للبدء والتطوير. يستخدم script التطوير nodemon الذي يراقب تغييرات الملفات ويُعيد تشغيل الخادم تلقائيًا. Node.js 18+ يأتي أيضًا بـ flag مدمج --watch — استخدم أيهما تفضل.

    json
    {
      "name": "my-api",
      "version": "1.0.0",
      "main": "src/app.js",
      "scripts": {
        "start": "node src/app.js",
        "dev": "nodemon src/app.js"
        // بديل حديث — لا حاجة لـ nodemon:
        // "dev": "node --watch src/app.js"
      },
      "dependencies": {
        "dotenv": "^16.0.0",
        "express": "^4.18.0"
      },
      "devDependencies": {
        "nodemon": "^3.0.0"
      }
    }
  3. 3

    أنشئ نقطة دخول Express

    أنشئ src/app.js. هذا الملف يُشغّل Express، يُركّب express.json() (محلل body لطلبات JSON)، يربط الـ routers، ويضيف احتياطيًا لـ 404 ومعالجًا مركزيًا للأخطاء. أبقِ هذا الملف خفيفًا — المنطق الفعلي في routes وcontrollers.

    javascript
    // src/app.js
    require("dotenv").config()
    const express = require("express")
    const usersRouter = require("./routes/users")
    
    const app = express()
    const PORT = process.env.PORT || 3000
    
    // Middleware
    app.use(express.json())
    
    // Routes
    app.use("/api/users", usersRouter)
    
    // احتياطي 404
    app.use((req, res) => {
      res.status(404).json({ error: "Not found" })
    })
    
    // معالج أخطاء مركزي
    app.use((err, req, res, next) => {
      console.error(err.stack)
      res.status(500).json({ error: "Internal server error" })
    })
    
    app.listen(PORT, () => {
      console.log(`Server running on http://localhost:${PORT}`)
    })
    
    module.exports = app
  4. 4

    أنشئ router للمستخدمين

    أنشئ src/routes/users.js. تجمع الـ Routers نقاط النهاية المتعلقة ببعضها. هذا الملف يربط أساليب HTTP والمسارات بدوال controller — لا يحتوي على منطق عمل بنفسه. استخدام express.Router() يضع routes كل مورد في ملفه الخاص.

    javascript
    // src/routes/users.js
    const express = require("express")
    const router = express.Router()
    const usersController = require("../controllers/usersController")
    
    router.get("/", usersController.getAll)
    router.get("/:id", usersController.getOne)
    router.post("/", usersController.create)
    router.put("/:id", usersController.update)
    router.delete("/:id", usersController.remove)
    
    module.exports = router
  5. 5

    اكتب controller بتخزين في الذاكرة

    أنشئ src/controllers/usersController.js. هنا تسكن معالجة الطلبات الفعلية. المصفوفة في الذاكرة مقصودة بسيطتها — في مشروع حقيقي استبدلها بمناداة قاعدة البيانات. Controllers يجب أن تبقى خفيفة أيضًا: تحقق من المدخلات، استدعِ طبقة البيانات، أرجع الاستجابة.

    javascript
    // src/controllers/usersController.js
    let users = [
      { id: 1, name: "Alice", email: "alice@example.com" },
      { id: 2, name: "Bob", email: "bob@example.com" },
    ]
    let nextId = 3
    
    exports.getAll = (req, res) => {
      res.json(users)
    }
    
    exports.getOne = (req, res) => {
      const user = users.find((u) => u.id === Number(req.params.id))
      if (!user) return res.status(404).json({ error: "User not found" })
      res.json(user)
    }
    
    exports.create = (req, res) => {
      const { name, email } = req.body
      if (!name || !email) {
        return res.status(400).json({ error: "name and email are required" })
      }
      const user = { id: nextId++, name, email }
      users.push(user)
      res.status(201).json(user)
    }
    
    exports.update = (req, res) => {
      const index = users.findIndex((u) => u.id === Number(req.params.id))
      if (index === -1) return res.status(404).json({ error: "User not found" })
      users[index] = { ...users[index], ...req.body, id: users[index].id }
      res.json(users[index])
    }
    
    exports.remove = (req, res) => {
      const index = users.findIndex((u) => u.id === Number(req.params.id))
      if (index === -1) return res.status(404).json({ error: "User not found" })
      users.splice(index, 1)
      res.status(204).send()
    }
  6. 6

    اختبر كل نقطة نهاية

    شغّل خادم التطوير واختبر العمليات الخمس. استخدم curl أو استورد هذه الأوامر إلى Postman.

    bash
    npm run dev
    
    # عرض جميع المستخدمين
    curl http://localhost:3000/api/users
    
    # جلب مستخدم واحد
    curl http://localhost:3000/api/users/1
    
    # إنشاء مستخدم
    curl -X POST http://localhost:3000/api/users \
      -H "Content-Type: application/json" \
      -d '{"name":"Carol","email":"carol@example.com"}'
    
    # تحديث مستخدم
    curl -X PUT http://localhost:3000/api/users/3 \
      -H "Content-Type: application/json" \
      -d '{"name":"Caroline"}'
    
    # حذف مستخدم
    curl -X DELETE http://localhost:3000/api/users/3
  7. 7

    استخدم رموز HTTP الصحيحة

    الرموز الصحيحة هي ما يميز API احترافيًا عن لعبة. اتّبع هذه الأعراف في كل معالج:

    • 200 OK — GET وPUT وPATCH الناجح
    • 201 Created — POST ناجح أنشأ موردًا
    • 204 No Content — DELETE ناجح (بدون body)
    • 400 Bad Request — مدخلات غير صحيحة، حقول مطلوبة مفقودة
    • 404 Not Found — المورد غير موجود
    • 422 Unprocessable Entity — JSON صالح لكن يفشل في قواعد العمل
    • 500 Internal Server Error — استثناء غير معالج (نادرًا ما يصل للعميل)
  8. 8

    أضف هيكل مشروع قابل للتوسع

    التخطيط المسطّح الحالي يصلح لمورد أو مورين. مع نمو المشروع، نظّمه هكذا. طبقة قاعدة البيانات منفصلة عن controller حتى تتمكن من استبدال التخزين دون لمس منطق المسارات.

    bash
    src/
    ├── app.js            # نقطة دخول — تشغيل Express وتركيب routers
    ├── routes/
    │   ├── users.js      # تعريفات routes لـ /api/users
    │   └── posts.js      # تعريفات routes لـ /api/posts
    ├── controllers/
    │   ├── usersController.js
    │   └── postsController.js
    ├── models/           # طبقة الوصول لقاعدة البيانات (استعلامات، ORM)
    │   ├── User.js
    │   └── Post.js
    ├── middleware/
    │   ├── auth.js       # التحقق من JWT
    │   └── validate.js   # مُغلّف التحقق من المدخلات
    └── config/
        └── db.js         # إعداد اتصال قاعدة البيانات

نصائح ومحاذير

  • ركّب `express.json()` قبل routes لا بعدها — الـ middleware يعمل بالترتيب. نسيان هذا هو السبب الشائع لكون `req.body` غير معرّف أحيانًا.
  • تحقق دائمًا من أن `req.params.id` رقم صحيح قبل البحث في قاعدة البيانات — معرّف غير رقمي يمكن أن يسبب أخطاء غير متوقعة في الاستعلام.
  • استخدم `express.Router()` لكل مورد. تجميع routes في نفس `app.js` يصلح للعروض لكنه يصبح غير قابل للإدارة بعد ثلاثة أو أربعة endpoints.
  • عند استبدال التخزين في الذاكرة بقاعدة بيانات، أبقِ توقيعات controller كما هي — فقط دوال model تتغير. هذا يجعل إعادة الهيكلة ميكانيكية.

خاتمة

يمنحك Express طبقة توجيه وخط أنابيب middleware. كل ما تبنيه فوق ذلك — controllers وmodels والتحقق — هو JavaScript عادي. هذه البساطة ميزة: يمكنك قراءة المشروع كاملًا دون أن يعترض سحر الإطار طريقك. بمجرد إتقان هذا الهيكل، إضافة قاعدة بيانات ومصادقة والتحقق من المدخلات هو مسألة وضع المكتبات الصحيحة في الطبقات الصحيحة.

#Node.js #Express #API
العودة إلى جميع الأدلة

هل تحتاج مساعدة في مشروعك؟

احجز استشارة مجانية لمدة 30 دقيقة لمناقشة تحدياتك التقنية واستكشاف الحلول معًا.