3.1إكسبريس (Express) : الطرق والوسائط والطلبات والردود
الأساسي في 30 ثانية
- إكسبريس (Express) يُحسّن الوحدة http : توجيه نظيف (app.get/post/put/delete)، ومعاملات ديناميكية (/users/:id ← req.params.id)، وردود بسطر واحد (res.json).
- الوسيط (middleware) هو المفهوم المفتاح : دالة (req, res, next) يعبرها كل طلب ؛ تتصرف ثم تنادي next() أو ترد لوقف السلسلة.
- ترتيب الخط مهم : المحلل أولا (express.json())، ثم التحقق والمصادقة، والرد أخيرا بالحالة الصحيحة.
حالة مصغرة متسلسلة — ساليم يستبدل سلسلة if بإكسبريس
ساليم، مطور مبتدئ في الجزائر، يقدم فهرسا مصغرا بالوحدة http الأصلية : سلسلة من if على req.url و req.method، وجسم POST يُحلل يدويا، وترويسات توضع واحدة واحدة. يعيد كتابة كل ذلك مع إكسبريس (Express) : app.use(express.json()) لتحليل الجسم، و app.get('/produits/:id') للبطاقات الديناميكية، ووسيط (middleware) يسجل كل طلب، و res.status(201).json() للإنشاءات. نفس الخادم، وكود أوضح بثلاث مرات.
هذه الحالة نفسها تعود في الدرس والمخطط والنص الجاهز وتحدي 48 ساعة.
1. التوجيه (routing) و req/res المُثراة
إكسبريس (Express) هو إطار الوب المرجعي لنود : بسيط ومرن، ومبني على الوحدة http (القسم 2-4). التوجيه (routing) يربط طريقة HTTP وعنوان URL بمعالج : app.get('/users', handler)، و app.post('/users', handler)، ومثلها لـ put و patch و delete. الطرق الديناميكية تلتقط مقاطع : app.get('/users/:id') يجعل المعرف مقروءا في req.params.id.
الكائنات مُثراة مقارنة بالأصلي. جهة الطلب : req.params (معاملات الطريق)، و req.query (سلسلة الاستعلام بعد ؟)، و req.body (الجسم المحلل، المتاح بفضل express.json()). جهة الرد : res.json(data) يرسل JSON بطريقة واحدة، و res.status(201).json(...) يثبت الحالة ثم يرسل، و res.send و res.redirect يغطيان الحالات الأخرى. يربح ساليم الأساسي : لا تحليل يدوي بعد، وطرق مقروءة، وردود صريحة.
2. الوسيط (middleware) : خط ترتيبه مهم
الوسيط (middleware) هو المفهوم المفتاح في إكسبريس : دالة (req, res, next) تُنفَّذ أثناء معالجة طلب. يمكنها فحص req و res أو تعديلهما (إرفاق req.user بعد المصادقة)، وتنفيذ كود (التسجيل والتحقق والقياس)، ثم مناداة next() للمرور إلى الوسيط التالي — أو إرسال رد لوقف السلسلة (مثلا إرجاع 401 دون الذهاب أبعد).
يعبر كل طلب خط أنابيب (pipeline) بترتيب الإعلان : express.json() الذي يحلل الجسم، ووسائطكم (السجل والمصادقة والتحقق)، ثم المعالج النهائي الذي يرد. كل شيء وسيط : التحليل والملفات الثابتة والمصادقة وتدبير الأخطاء. ومنعكسا ساليم : الحلل قبل التحقق (وإلا فـ req.body فارغ) و مناداة next() أو الرد دائما (وإلا بقي الطلب عالقا). نطبق وسيطا عموما (app.use(...)) أو على طريق دقيق.
الحلقة المفقودة
وسيط لا يمرر المهمة يعلق الجميع.
🔎 مثال ملموس — API فهرس مصغرة في أسطر قليلة
يعيد ساليم كتابة خادمه الأصلي مع إكسبريس.
const express = require('express');
const app = express();
app.use(express.json());
app.use((req, res, next) => { console.log(req.method, req.url); next(); });
app.get('/produits/:id', (req, res) => res.json({ id: req.params.id }));
app.post('/produits', (req, res) => res.status(201).json(req.body));
app.listen(3000);
القراءة : المسجل ينادي next()، والطريق الديناميكي يقرأ req.params، والإنشاء يرجع 201.
الدرس : التحليل التلقائي يحذف كل كود الخادم الأصلي اليدوي.
مفردات القسم
- إكسبريس (Express)
- إطار وب بسيط مرجعي لنود، مبني على الوحدة http ؛ يجلب التوجيه والوسائط و req/res المُثراة.
مثال بسيط: يعيد ساليم فيه كتابة فهرسه في أسطر قليلة مقروءة.
ما ليس كذلك: معوض لنود يستغني عن الوحدة http.
رد فعل: استعماله لكل API أو تطبيق وب بدل الأصلي الخام.
- التوجيه (routing)
- ربط طريقة HTTP وعنوان URL بمعالج : app.get('/users', ...) و app.post(...)، مع طرق ديناميكية '/users/:id'.
مثال بسيط: GET /produits/7 الملتقط بـ app.get('/produits/:id').
ما ليس كذلك: سلسلة من if على req.url في خادم أصلي.
رد فعل: طريق لكل نية، بالفعل الصحيح لـ HTTP.
- الوسيط (middleware)
- دالة (req, res, next) تُنفَّذ أثناء المعالجة ؛ تتصرف في req/res ثم تنادي next() أو ترسل ردا.
مثال بسيط: مسجل ساليم الذي يدون كل طلب ثم يمرر المهمة.
ما ليس كذلك: مجرد دالة نفعية غير مربوطة أبدا بالخط.
رد فعل: الإنهاء دائما بـ next() أو برد.
- خط الوسائط
- سلسلة مرتبة من الوسائط يعبرها كل طلب : التحليل والسجل والمصادقة والتحقق والمعالج النهائي.
مثال بسيط: express.json() ثم التحقق ثم المعالج عند ساليم.
ما ليس كذلك: معالجات معزولة دون ترتيب ولا اشتراك.
رد فعل: الحلل أولا، ثم التحقق، والرد أخيرا.
- req / res المُثراة
- كائنا إكسبريس : req.params و req.query و req.body جهة الطلب ؛ و res.json و res.status و res.send و res.redirect جهة الرد.
مثال بسيط: req.params.id مقروء و res.status(201).json() مرسَل.
ما ليس كذلك: الـ req/res الخام للوحدة http دون مساعدة.
رد فعل: قراءة الجسم في req.body، والرد مع res.json().
في التطبيق — بناء تطبيق مع إكسبريس
- أنشئوا تطبيق إكسبريس (const app = express())، وأضيفوا app.use(express.json()) لتحليل JSON، واشغلوا مع app.listen(3000).
- عرفوا طرقا : app.get('/users', ...) و app.post('/users', ...)، وطريقا ديناميكيا app.get('/users/:id', ...) (اقرؤوا req.params.id).
- أرجعوا ردودا بالطرق المُثراة : res.json(data) و res.status(201).json(...)، واقرؤوا الجسم مع req.body.
- اكتبوا وسيطكم الخاص (req, res, next) الذي يسجل كل طلب، وطبقوه مع app.use(...) ونادوا next().
نص جاهز للقول — عرض API إكسبريس (30 ثانية)
« بنيت API الفهرس مع إكسبريس : express.json لتحليل الجسم، وطريق ديناميكي /produits/:id مقروء في req.params، ووسيط يسجل ثم ينادي next، وردود res.json بالحالة الصحيحة، 201 للإنشاءات. مُختبَر في المتصفح على localhost:3000. »
يُقال في المراجعة ؛ وتُعرَض الطريق الديناميكية وسجل طلب.
نموذج نسخ-لصق — خادم إكسبريس أدنى
const express = require('express');
const app = express();
app.use(express.json());
app.use((req, res, next) => {
console.log(req.method, req.url);
next();
});
app.get('/produits/:id', (req, res) => {
res.json({ id: req.params.id });
});
app.post('/produits', (req, res) => {
res.status(201).json(req.body);
});
app.listen(3000, () => console.log('OK port 3000'));
مستقل
تكفي API عروض أسعار بإكسبريس : طريقا GET/POST ووسيط سجل، دون إطار ثقيل.
مقاولة صغيرة في الجزائر
يعرض ساليم الفهرس الداخلي : طرق ديناميكية حسب مرجع المنتج، وحالات 200/201/404 محترَمة.
فريق منتج
توحيد الخط (json والسجل والمصادقة والتحقق) ليرث كل طريق نفس الأساس.
مبتدئ
هذا الأسبوع : خادم واحد، وطريق GET ديناميكية واحدة، ووسيط واحد ينادي next().
✓ ممارسات جيدة
- التفكير « خط أنابيب » : كل شيء وسيط، والترتيب مهم.
- استعمال express.json() لتحليل الجسم، و res.json() للرد.
- تغليف الاهتمامات العرضية (المصادقة والسجل) في وسائط قابلة لإعادة الاستعمال.
✗ أخطاء شائعة
- نسيان مناداة next() (يبقى الطلب عالقا).
- سوء ترتيب الوسائط (التحقق قبل التحليل).
- وضع كل المنطق في معالج واحد بدل تركيب وسائط.
النقاط الأساسية
- إكسبريس = إطار وب نود المرجعي (مبني على http) : يبسط التوجيه والتحليل وتدبير الطلبات.
- التوجيه : app.get/post/put/delete('/chemin', handler) ؛ طرق ديناميكية /users/:id ← req.params.id.
- الوسيط (req, res, next) هو المفهوم المفتاح : يتصرف أثناء المعالجة، ثم next() يمرر للتالي — خط أنابيب.
- كل شيء وسيط : express.json() والثابت والمصادقة وتدبير الأخطاء ووسائطكم الخاصة (app.use أو لكل طريق).
تحدي 48 ساعة — طبّق غدا
ابنوا API إكسبريس واحدة مع طريق ديناميكية واحدة و وسيط سجل واحد ينادي next().
- أذكر دور next() دون تردد.
- أقرأ req.params و req.query و req.body.
- الـ API عندي ترد بـ res.json() بالحالة الصحيحة.
أسئلة شائعة
ما هو الوسيط بالضبط، ولماذا هو المفهوم المركزي لإكسبريس ؟
الوسيط دالة (req, res, next) تُنفَّذ أثناء معالجة طلب. يمكنه فحص الطلب، وتعديل req/res (مثلا إرفاق req.user)، وتنفيذ كود (التسجيل والتحقق)، ثم يقرر : مناداة next() للمرور للتالي، أو إرسال رد لوقف السلسلة (وسيط مصادقة يرجع 401). وهو مركزي لأن كل شيء وسيط في إكسبريس : التحليل (express.json()) والثابت والمصادقة والتحقق وتدبير الأخطاء — ومعالجات الطرق هي الحلقة الأخيرة. التفكير « خط مرتب » بدل « دوال معزولة » هو فهم إكسبريس.
لماذا إكسبريس شائع جدا، وهل توجد بدائل ؟
بسيط وغير مُملٍ (توجيه + وسائط، وحرية الهيكلة)، وسهل البدء، وناضج ومُجرَّب، ونظام ضخم من الوسائط ومعيار فعلي منتظر من مطور Node. حدوده (خيارات تُتخذ ذاتيا، ولا هيكلة مفروضة) تحفز بدائل مثل Fastify و Koa و NestJS في المشاريع الكبيرة. لكن للتعلم ثم الإنتاج السريع، يبقى إكسبريس الخيار الافتراضي — الذي يتقنه ساليم أولا في الجزائر.
في وسيط إكسبريس، ماذا يفرض عقد (req, res, next) ؟