المحطّة ٢: تصميم الواجهة البرمجية (API) ونموذج البيانات
العقد قبل البناء: نموذج البيانات والمسارات ورموز الحالة. ⏱ نحو 24 دقيقة.
- تصمّم نموذج بياناتٍ يعبّر عن حالة الموارد.
- تشتقّ مسارات
RESTمن قصص المستخدم بطرقٍ ورموزٍ صحيحة. - توحّد شكل الردود والأخطاء.
- تبني «عقدًا» يفصل الواجهة عن الخادم.
١الـ API عقدٌ بين طبقتين
مشروعنا طبقتان: واجهة React وخادم Express. بينهما عقدٌ هو الـ API: مجموعة مساراتٍ متّفقٌ عليها، كلٌّ له طريقةٌ (GET/POST…) ومدخلٌ وشكل ردّ. نصمّم هذا العقد قبل كتابة أيّ طبقة، فتُبنيان بالتوازي دون أن تنتظر إحداهما الأخرى — كما تعلّمت في مقرّر 242.
الـ API الجيّد يجعل الواجهة والخادم مستقلّين: لو غيّرت شكل الواجهة لاحقًا لن يتأثّر الخادم، والعكس، ما دام العقد ثابتًا.
٢نموذج البيانات: ما شكل «الموعد»؟
كل موعدٍ كائنٌ بسيط. الحقل المفتاح هو bookedBy: فارغٌ (null) يعني «متاح»، وغير فارغٍ يعني «محجوز» لمن فيه:
// نموذج البيانات: موعد (Appointment){ "id": 1, "doctor": "د. منى", "time": "2026-10-25 09:00", "bookedBy": null // null = متاح، أو اسم المريض الذي حجزه}
بهذا الحقل وحده نفرّق المتاح من المحجوز، ونمنع الحجز المزدوج: لا نحجز إلّا إذا كان bookedBy === null.
٣تصميم المسارات (Endpoints)
نشتقّ المسارات من قصص المستخدم. المورد جمعٌ (appointments)، والطريقة هي الفعل، ورمز الحالة يصف النتيجة — كلّها من مقرّر 242:
| الطريقة والمسار | يفعل | النجاح | الفشل |
|---|---|---|---|
GET /api/appointments | كل المواعيد (?status=free للمتاح) | 200 | — |
POST /api/appointments/:id/book | يحجز موعدًا متاحًا | 200 | 404 غير موجود · 409 محجوز · 422 بلا اسم |
POST /api/appointments/:id/cancel | يلغي حجزًا | 200 | 404 |
POST /api/login | يسجّل الدخول ويعيد رمزًا | 200 | 401 |
مثالٌ على العقد — طلبٌ وردّ لحجزٍ ناجح:
POST /api/appointments/1/book HTTP/1.1 Content-Type: application/json {"patient": "سعود"}
HTTP/1.1 200 OK Content-Type: application/json {"data": {"id": 1, "doctor": "د. منى", "bookedBy": "سعود"}}
٤شكلٌ موحّدٌ للردود والأخطاء
نثبّت غلافًا واحدًا لكل الردود يسهّل على الواجهة التعامل معها (كما في 242):
- النجاح:
{"data": …}(وللقوائم نضيف"meta": {"total": n}). - الخطأ:
{"error": {"code": "CONFLICT", "message": "الموعد محجوز"}}.
توقّع وتحقّق
أيّ مسارٍ يتبع تصميم REST؟
ما رمز الحالة لمحاولة حجز موعدٍ محجوزٍ أصلًا؟
كيف نميّز الموعد المتاح في نموذجنا؟
ما فائدة توحيد شكل الرد {data}/{error}؟
الخلاصة
- الـ
APIعقدٌ يُصمَّم قبل الطبقتين فتُبنيان بالتوازي. - حقل
bookedBy(null/اسم) يميّز المتاح من المحجوز ويمنع الحجز المزدوج. - المورد جمعٌ، والطريقة فعلٌ، ورمز الحالة يصف النتيجة (409 للتعارض، 422 للمدخل).
- غلافٌ موحّد:
{data}للنجاح و{error:{code,message}}للخطأ. - كل قصّة مستخدمٍ يجب أن يقابلها مسارٌ في العقد.
تحدٍّ تصميمي: عقد الـ API لنظام الحجز
تصميميصمّم الواجهة البرمجية لمشروعك: نموذج البيانات، وجدول المسارات بطرقها ورموز حالتها، وشكلٌ موحّدٌ للردود والأخطاء. سنُنفّذ هذا العقد في المحطّات القادمة.
- نموذج بيانات «الموعد» بحقوله.
- جدول مساراتٍ يغطّي كل قصص المحطّة 1.
- رمز حالةٍ مناسبٌ لكل نتيجة (نجاح وفشل).
- شكلٌ موحّدٌ للردّ الناجح وللخطأ.