تخطَّ إلى المحتوى

🔌 شرح REST APIs

HATEOAS ومستويات نضج REST

الدرس 30 من 32· ⏱ 3 دقائق قراءة

سؤال قبل ما نبدأ

كل الدروس السابقة علّمتك تبني REST API فيه موارد، طرق HTTP صحيحة، وأكواد حالة دقيقة. بس هل هالواجهة "RESTful" فعلًا بالمعنى الأصلي يلي وصفه Roy Fielding بأطروحته سنة 2000؟ الجواب غالبًا: لأ — وفيه قيد أخير غايب.

HATEOAS — القيد الرابع

HATEOAS اختصار لـ Hypermedia As The Engine Of Application State. الفكرة: بدل ما يحفظ العميل (Client) روابط كل إجراء ممكن بالكود مسبقًا، الخادم يرسلها ضمن الاستجابة نفسها، تمامًا متل ما متصفح الويب بيتنقّل بين الصفحات عبر روابط <a> موجودة بالصفحة، مو عناوين محفوظة بذاكرة المتصفح.

// بدون HATEOAS — العميل لازم يعرف مسبقًا كل الروابط الممكنة
{ "id": 9, "status": "pending" }

// مع HATEOAS — الاستجابة نفسها بتقول شو الإجراءات المتاحة الآن
{
  "id": 9,
  "status": "pending",
  "links": [
    { "rel": "self",   "href": "/orders/9" },
    { "rel": "cancel", "href": "/orders/9/cancel", "method": "POST" },
    { "rel": "pay",    "href": "/orders/9/pay",    "method": "POST" }
  ]
}

لاحظ الفرق: لما تصير حالة الطلب "shipped" بدل "pending"، الخادم ببساطة ما بيرجّع رابط cancel أو pay بعد — العميل بيعرف الإجراءات المسموحة من الاستجابة الحيّة، مو من افتراضات مكتوبة بالكود.

💡 هاي بالضبط نفس فكرة استعراض موقع ويب: ما بتحفظ روابط الموقع كله بذاكرتك، بس بتضغط اللي قدامك بالصفحة.

Richardson Maturity Model

المطوّر Leonard Richardson اقترح نموذجًا لتصنيف مدى قرب أي واجهة من REST الأصلي — أربعة مستويات، كل واحد فيها بضيف قيدًا فوق يلي قبله:

المستوىالاسمالوصف
0RPC عبر HTTPنقطة نهاية واحدة فقط، كل العمليات POST إلها، والتمييز بين الإجراءات داخل جسم الطلب
1المواردروابط متعددة، كل مورد إله رابطه الخاص (/orders/9، /users/3)
2طرق HTTP وأكواد الحالةاستخدام GET/POST/PUT/DELETE الصحيحة، وأكواد حالة دقيقة (201، 404، 409...) — هون معظم REST APIs الحقيقية
3HATEOASالاستجابة نفسها فيها روابط اكتشاف ذاتية للإجراءات المتاحة تاليًا
المستوى 0:  POST /api  { "action": "cancelOrder", "id": 9 }
المستوى 1:  POST /orders/9/cancel
المستوى 2:  POST /orders/9/cancel  →  200 OK  (طريقة وكود حالة صحيحين)
المستوى 3:  GET  /orders/9  →  الاستجابة فيها رابط "cancel" فقط إذا كانت الحالة تسمح فعلًا

مشروعك الحالي — لو مشيت بالدروس السابقة (الموارد بلغة 08، الطرق بلغة 04، الأكواد بلغة 05) — واصل غالبًا للمستوى 2. وهذا طبيعي وكافٍ لأغلب المشاريع.

ليش المستوى 3 نادر بالواقع؟

رغم إنه المستوى الأعلى نظريًا، أغلب REST APIs المشهورة (بما فيها واجهات شركات كبيرة) بتتوقف عند المستوى 2. الأسباب العملية:

  • التوثيق (Swagger/OpenAPI) بيغطي نفس الحاجة عمليًا — العميل بيعرف الروابط المتاحة من التوثيق مباشرة، مو لازم يكتشفها ديناميكيًا.
  • تعقيد إضافي على الخادم — لازم تحسب "شو الإجراءات المسموحة الآن" بكل استجابة، مو مجرد ترجيع بيانات.
  • معظم العملاء (SPA، موبايل) مكتوبين مسبقًا لمسارات ثابتة — الاكتشاف الديناميكي ميزة لعملاء عامّين (generic clients)، وهاي نادرة بالتطبيقات الحقيقية.

💡 HATEOAS بيلمع فعليًا لما تكون حالة المورد بتتغيّر بشكل يغيّر الإجراءات المتاحة ديناميكيًا — متل حالة طلب (pending → shipped → delivered) وين كل حالة إلها إجراءات مختلفة.

نسخة عملية خفيفة

مو لازم تطبّق HATEOAS بالكامل عشان تستفيد من فكرته. إضافة رابط self بسيط لكل استجابة تكلفتها بسيطة وبتحسّن قابلية الاستكشاف:

app.get("/api/articles/:id", (req, res) => {
  const article = getArticle(req.params.id);
  res.json({
    ...article,
    links: [{ rel: "self", href: `/api/articles/${article.id}` }],
  });
});

خلاصة

  • HATEOAS هو القيد الرابع في REST الأصلي: روابط الاكتشاف تكون ضمن الاستجابة نفسها.
  • Richardson Maturity Model يقيس نضج واجهتك بأربعة مستويات، من RPC بسيط إلى Hypermedia كامل.
  • معظم REST APIs الفعلية — وهذا مقبول تمامًا — تتوقف عند المستوى 2. المستوى 3 خيار إضافي لحالات محددة، مو معيار إلزامي.

🎯 التالي: رفع الملفات في REST API

شرح HATEOAS ومستويات نضج REST — REST APIs بالعربي
HATEOAS ومستويات نضج RESTREST APIs بالعربي · The Code Fix

📚 لمزيد من التعمّق في REST APIs، راجِع توثيق HTTP على MDN.

هل كان هذا الدرس مفيدًا؟