Node.js و Express

مقدمة إلى Express.js

20 دقيقة الدرس 7 من 40

ما هو Express.js؟

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

لماذا نستخدم Express؟

  • البساطة: يبسط Express عملية بناء خوادم الويب مقارنة بوحدة HTTP الخام في Node.js
  • المرونة: التصميم غير المتحيز يسمح لك بهيكلة تطبيقك بالطريقة التي تريدها
  • توجيه قوي: نظام توجيه قوي للتعامل مع مسارات URL المختلفة
  • دعم البرمجيات الوسيطة: نظام بيئي واسع من البرمجيات الوسيطة لإضافة الوظائف
  • الأداء: حمل إضافي ضئيل، مبني على Node.js من أجل السرعة
  • المجتمع: مجتمع كبير مع وثائق وموارد واسعة
ملاحظة: لا يجبرك Express على استخدام أي قاعدة بيانات أو محرك قوالب أو هندسة معمارية محددة. لديك حرية كاملة لاختيار أدواتك وتنظيم الكود الخاص بك.

تثبيت Express

قبل تثبيت Express، تأكد من تثبيت Node.js و NPM على نظامك. ثم اتبع هذه الخطوات:

الخطوة 1: إنشاء دليل المشروع

mkdir my-express-app cd my-express-app

الخطوة 2: تهيئة NPM

npm init -y

الخطوة 3: تثبيت Express

npm install express

هذا الأمر يثبت Express ويضيفه إلى تبعيات package.json الخاصة بك:

{ "dependencies": { "express": "^4.18.2" } }
نصيحة: للتطوير، قم أيضًا بتثبيت Nodemon لإعادة تشغيل الخادم تلقائيًا عند تغيير الملفات: npm install --save-dev nodemon

إنشاء أول خادم Express

لنقم بإنشاء خادم Express بسيط. أنشئ ملفًا باسم app.js:

// استيراد Express const express = require('express'); // إنشاء تطبيق Express const app = express(); // تعريف المنفذ const PORT = 3000; // إنشاء مسار بسيط app.get('/', (req, res) => { res.send('مرحبا بالعالم!'); }); // بدء تشغيل الخادم app.listen(PORT, () => { console.log(`الخادم يعمل على http://localhost:${PORT}`); });

تشغيل الخادم الخاص بك

قم بتشغيل الخادم الخاص بك مع Node:

node app.js

أو إذا قمت بتثبيت Nodemon، أضف هذا السكريبت إلى package.json الخاص بك:

"scripts": { "start": "node app.js", "dev": "nodemon app.js" }

ثم قم بالتشغيل:

npm run dev

افتح متصفحك وانتقل إلى http://localhost:3000. يجب أن ترى "مرحبا بالعالم!" معروضة.

فهم الكود

دعنا نحلل ما يحدث في أول خادم Express لدينا:

1. استيراد Express

const express = require('express');

هذا السطر يستورد وحدة Express باستخدام دالة require() الخاصة بـ Node.js.

2. إنشاء نسخة تطبيق

const app = express();

هذا ينشئ كائن تطبيق Express. كائن app له طرق لتوجيه طلبات HTTP، وتكوين البرمجيات الوسيطة، وعرض طرق عرض HTML، والمزيد.

3. تعريف مسار

app.get('/', (req, res) => { res.send('مرحبا بالعالم!'); });

هذا يعرّف معالج مسار لطلبات GET إلى المسار الجذر ('/'). عندما يأتي طلب، يستدعي Express دالة الاستدعاء مع معاملين:

  • req (الطلب): يحتوي على معلومات حول الطلب الوارد
  • res (الاستجابة): يوفر طرقًا لإرسال استجابة إلى العميل

4. بدء الخادم

app.listen(PORT, () => { console.log(`الخادم يعمل على http://localhost:${PORT}`); });

هذا يخبر Express ببدء الاستماع للطلبات على المنفذ المحدد. تعمل دالة الاستدعاء بمجرد بدء الخادم بنجاح.

كائن الطلب (req)

يمثل كائن الطلب طلب HTTP ويحتوي على خصائص لسلسلة الاستعلام والمعاملات والجسم والرؤوس والمزيد.

خصائص الطلب الشائعة

req.params

يحتوي على معاملات المسار (أجزاء URL المسماة):

app.get('/users/:id', (req, res) => { console.log(req.params.id); // الوصول إلى معامل :id res.send(`معرف المستخدم: ${req.params.id}`); });

req.query

يحتوي على معاملات سلسلة استعلام URL:

// URL: /search?term=express&page=1 app.get('/search', (req, res) => { console.log(req.query.term); // 'express' console.log(req.query.page); // '1' res.send(`البحث عن: ${req.query.term}`); });

req.body

يحتوي على البيانات المرسلة في جسم الطلب (يتطلب برمجية وسيطة):

app.use(express.json()); // برمجية وسيطة لتحليل JSON app.post('/users', (req, res) => { console.log(req.body.name); console.log(req.body.email); res.send('تم إنشاء المستخدم'); });

req.headers

يحتوي على رؤوس طلب HTTP:

app.get('/info', (req, res) => { console.log(req.headers['user-agent']); console.log(req.headers['content-type']); res.send('تم تسجيل الرؤوس'); });

req.method

طريقة HTTP للطلب (GET، POST، PUT، DELETE، إلخ):

app.all('/test', (req, res) => { console.log(req.method); // GET, POST, PUT, إلخ res.send(`تم استلام طلب ${req.method}`); });

req.path

جزء المسار من عنوان URL للطلب:

app.get('/about', (req, res) => { console.log(req.path); // '/about' res.send('صفحة حول'); });

req.ip

عنوان IP البعيد للطلب:

app.get('/', (req, res) => { console.log(req.ip); // عنوان IP للعميل res.send('تم تسجيل IP'); });

كائن الاستجابة (res)

يمثل كائن الاستجابة استجابة HTTP التي يرسلها Express عند تلقي طلب. يوفر طرقًا لإرسال أنواع مختلفة من الاستجابات.

طرق الاستجابة الشائعة

res.send()

يرسل استجابة من أنواع مختلفة (يحدد Content-Type تلقائيًا):

app.get('/text', (req, res) => { res.send('استجابة نص عادي'); }); app.get('/html', (req, res) => { res.send('<h1>استجابة HTML</h1>'); }); app.get('/json', (req, res) => { res.send({ name: 'أحمد', age: 30 }); });

res.json()

يرسل استجابة JSON (يحدد Content-Type صراحةً إلى application/json):

app.get('/api/user', (req, res) => { res.json({ id: 1, name: 'أحمد محمد', email: 'ahmed@example.com' }); });

res.status()

يحدد رمز حالة HTTP:

app.get('/not-found', (req, res) => { res.status(404).send('الصفحة غير موجودة'); }); app.post('/users', (req, res) => { res.status(201).json({ message: 'تم إنشاء المستخدم' }); });

res.sendFile()

يرسل ملفًا كاستجابة:

const path = require('path'); app.get('/download', (req, res) => { const filePath = path.join(__dirname, 'files', 'document.pdf'); res.sendFile(filePath); });

res.redirect()

إعادة التوجيه إلى عنوان URL مختلف:

app.get('/old-page', (req, res) => { res.redirect('/new-page'); }); app.get('/external', (req, res) => { res.redirect('https://www.google.com'); });

res.render()

يعرض قالب طريقة عرض (يتطلب محرك قوالب):

app.get('/profile', (req, res) => { res.render('profile', { name: 'أحمد', age: 30 }); });

res.set() أو res.header()

يحدد رؤوس الاستجابة:

app.get('/custom-header', (req, res) => { res.set('Content-Type', 'text/plain'); res.set('X-Custom-Header', 'قيمتي'); res.send('استجابة برؤوس مخصصة'); });

res.cookie()

يحدد ملفات تعريف الارتباط في الاستجابة:

app.get('/set-cookie', (req, res) => { res.cookie('username', 'ahmed', { maxAge: 900000, httpOnly: true }); res.send('تم تعيين ملف تعريف الارتباط'); });
ملاحظة: العديد من طرق الاستجابة (مثل res.send()، res.json()، res.redirect()) تنهي دورة الطلب والاستجابة. بمجرد استدعاء إحدى هذه الطرق، لا يمكنك إرسال استجابة أخرى.

تسلسل الطرق

يمكن تسلسل طرق استجابة Express للحصول على كود أنظف:

app.get('/users/:id', (req, res) => { res .status(200) .set('Content-Type', 'application/json') .json({ id: req.params.id, name: 'أحمد محمد' }); });

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

من المهم معالجة الأخطاء بشكل صحيح في تطبيقات Express الخاصة بك:

app.get('/file', (req, res) => { const filePath = path.join(__dirname, 'nonexistent.txt'); // التحقق من وجود الملف قبل الإرسال const fs = require('fs'); if (!fs.existsSync(filePath)) { return res.status(404).send('الملف غير موجود'); } res.sendFile(filePath); });

معالجة أخطاء 404

للمسارات التي لا تطابق أي مسارات محددة، أضف معالج شامل في النهاية:

// جميع مساراتك هنا... // معالج 404 (يجب تعريفه أخيرًا) app.use((req, res) => { res.status(404).send('<h1>404 - الصفحة غير موجودة</h1>'); });

مثال كامل

إليك تطبيق Express أكثر اكتمالاً يوضح مفاهيم مختلفة:

const express = require('express'); const app = express(); const PORT = 3000; // برمجية وسيطة لتحليل أجسام JSON app.use(express.json()); // برمجية وسيطة لتحليل أجسام مشفرة بـ URL app.use(express.urlencoded({ extended: true })); // مسار الصفحة الرئيسية app.get('/', (req, res) => { res.send('<h1>مرحبًا بك في Express!</h1>'); }); // مسار حول app.get('/about', (req, res) => { res.json({ name: 'تطبيق Express الخاص بي', version: '1.0.0', description: 'تعلم Express.js' }); }); // مسار مع معامل app.get('/users/:id', (req, res) => { const userId = req.params.id; res.json({ userId, message: `الحصول على المستخدم ${userId}` }); }); // مسار مع معاملات استعلام app.get('/search', (req, res) => { const { q, page = 1 } = req.query; res.json({ query: q, page: parseInt(page), results: [] }); }); // مسار POST app.post('/users', (req, res) => { const { name, email } = req.body; res.status(201).json({ message: 'تم إنشاء المستخدم', user: { name, email } }); }); // معالج 404 app.use((req, res) => { res.status(404).json({ error: 'المسار غير موجود' }); }); // بدء الخادم app.listen(PORT, () => { console.log(`الخادم يعمل على http://localhost:${PORT}`); });
نصيحة: استخدم أدوات مثل Postman أو Insomnia أو امتداد Thunder Client لـ VS Code لاختبار طلبات POST و PUT و DELETE وإرسال بيانات JSON إلى نقاط نهاية API الخاصة بك.

متغيرات البيئة

من الممارسات الجيدة استخدام متغيرات البيئة للتكوين مثل أرقام المنافذ:

// تثبيت dotenv: npm install dotenv require('dotenv').config(); const PORT = process.env.PORT || 3000; app.listen(PORT, () => { console.log(`الخادم يعمل على المنفذ ${PORT}`); });

أنشئ ملف .env:

PORT=3000 NODE_ENV=development
تحذير: لا تقم أبدًا بإيداع ملف .env الخاص بك في نظام التحكم في الإصدار (أضفه إلى .gitignore). قد يحتوي على معلومات حساسة مثل مفاتيح API وبيانات اعتماد قاعدة البيانات.
تمرين: أنشئ خادم API Express بسيطًا:
  1. قم بتهيئة مشروع Node.js جديد
  2. قم بتثبيت Express و Nodemon
  3. أنشئ ملف app.js مع المسارات التالية:
    • GET / - يعيد رسالة ترحيب
    • GET /api/books - يعيد مصفوفة من 3-5 كائنات كتاب (مع id و title و author)
    • GET /api/books/:id - يعيد كتابًا محددًا بواسطة ID
    • POST /api/books - يقبل جسم JSON ببيانات الكتاب ويعيد رسالة نجاح
    • GET /api/search - يقبل معامل استعلام ?title=... ويعيد الكتب المطابقة
  4. اختبر جميع المسارات باستخدام متصفح (لـ GET) و Postman/Thunder Client (لـ POST)
  5. أضف رموز الحالة المناسبة (200، 201، 404) إلى الاستجابات
  6. أضف معالج 404 للمسارات غير المحددة
  7. استخدم متغيرات البيئة لرقم المنفذ