أساسيات REST API

REST (Representational State Transfer) أسلوب معماري (Architectural Style) وصفه روي فيلدينغ (Roy Fielding) في أطروحته للدكتوراه عام ⁦2000⁩: مجموعة من القيود، لا بروتوكول ولا معيار. وواجهة REST تعرض موارد (Resources) — طلب شراء أو عميلاً أو مهمة — لكل منها معرّف URI. ويتعامل العملاء معها بطرق HTTP القياسية ويتبادلون تمثيلات (Representations) لها، غالباً بصيغة JSON.

مثال: واجهة لإدارة المهام تعرض المجموعة /tasks، ولكل مهمة عنوان URI خاص بها مثل /tasks/42. فالطلب GET /tasks/42 يعيد المهمة ⁦42⁩، وPATCH /tasks/42 مع {"done": true} يغيّر حقلاً واحداً، وDELETE /tasks/42 يحذفها. العنوان يسمّي الشيء، والطريقة تحدد ما يُفعل به، ورمز الحالة يخبرك بالنتيجة.

لماذا يهم

تتيح لك أعراف REST أن تتوقع السلوك الصحيح قبل أن ترسل أي طلب: الإنشاء يعيد 201 Created، والمورد المحذوف لا يعود موجوداً، والطريقة غير المدعومة تُرفض بالرمز 405. وحيثما خالفت الواجهة عرفاً دون توثيق، يُرجَّح أن يكتب مطورو العملاء شيفرة تتعامل معه بشكل خاطئ.

وتتضاعف كلفة عيب الواجهة بعدد عملائها. فحقل أُعيدت تسميته أو 500 لمدخلات سيئة قد يعطّل واجهة الويب الأمامية وتكامل أحد الشركاء وإصدارات التطبيق المثبتة على هواتف المستخدمين، مع أن أياً منها لم يتغير. ومعرفة الأعراف تحوّل ملاحظة «الواجهة تبدو غريبة» إلى توقعات دقيقة لحالات الاختبار.

الموارد وعناوين URI والتمثيلات وانعدام الحالة

يعرّف فيلدينغ REST بستة قيود، أحدها اختياري، منها انعدام الحالة (Stateless) والواجهة الموحّدة (Uniform Interface). وكثيراً ما تطبّقها الواجهات الموصوفة بأنها REST تطبيقاً جزئياً — فروابط الوسائط التشعبية (Hypermedia) التي تخبر العميل بما يمكنه فعله بعد ذلك تُترك غالباً — لذا احكم على الواجهة بعقدها أولاً، واستخدم أعراف REST لاكتشاف التناقضات. وأهم أربع أفكار للاختبار:

  • المورد (Resource): شيء مسمّى تعرضه الواجهة — مهمة أو مستخدم أو قائمة المهام. الموارد أسماء، والفعل يأتي من الطريقة: POST /tasks لا POST /createTask.
  • عنوان URI: معرّف المورد، وصيغته معرّفة في RFC 3986. ومن الأعراف الشائعة مجموعة بصيغة الجمع /tasks، وأعضاؤها /tasks/42، وموارد فرعية مثل /tasks/42/comments.
  • التمثيل (Representation): حالة المورد في صيغة محددة. يذكر العميل الصيغة التي يرسلها في Content-Type والصيغ التي يستطيع قراءتها في Accept.
  • انعدام الحالة (Statelessness): يحمل كل طلب كل ما يحتاجه الخادم لفهمه — بيانات الاعتماد مثل الرمز المميّز (Token)، والمعرّفات، ورقم الصفحة. ولا يحتفظ الخادم بسياق جلسة من الطلبات السابقة (أما الموارد المخزّنة نفسها فتبقى بالطبع)، فيمكن تكرار الطلب أو إرساله منفرداً أو معالجته على خادم آخر ويبقى معناه واحداً. واختبره على هذا الأساس: اطلب الصفحة ⁦3⁩ مباشرةً دون جلب الصفحتين ⁦1⁩ و⁦2⁩ أولاً.

ربط الطرق بعمليات CRUD

تشير CRUD إلى العمليات الأساسية على البيانات المخزنة: الإنشاء (Create) والقراءة (Read) والتحديث (Update) والحذف (Delete). وفي REST تمثّل كل عملية طريقةَ HTTP تُطبَّق على المجموعة أو على عنصر واحد. وقد تعرّفت إلى الطرق وإلى خاصيتَي كونها آمنة (Safe) ومتكافئة (Idempotent) في درس طرق HTTP؛ ويجمع الجدول بينها وبين الموارد.

والنمط وراء الجدول: تُنشئ على المجموعة، والخادم يختار عنوان URI للعنصر الجديد؛ وتقرأ المجموعة أو عنصراً واحداً؛ وتحدّث عنصراً واحداً أو تحذفه في عنوانه الخاص. أما التركيبات الخارجة عن الجدول — POST /tasks/42، أو PUT وPATCH وDELETE على المجموعة كلها — فلا تُتاح عادةً، ويجب أن تُقابَل بالرمز 405 Method Not Allowed.

في واجهة المهام، كل عملية CRUD طريقة واحدة على المجموعة أو على عنصر واحد؛ وكل تركيبة أخرى يجب رفضها بالرمز 405 مع ترويسة Allow.
الطريقةالمورد
/tasksالمجموعة/tasks/{id}عنصر واحد
GETالقراءةعرض قائمة المهام200 OK، وغالباً مقسّمة إلى صفحاتقراءة مهمة واحدة200 OK · و404 إن لم تكن موجودة
POSTالإنشاءإنشاء مهمة؛ والخادم يختار المعرّف201 Created + Locationلا تُتاح عادةً405 + Allow
PUTالتحديث: استبداللا تُتاح عادةً405 + Allowاستبدال المهمة كاملة200 أو 204 · و201 إن أنشأ المهمة
PATCHالتحديث: بعض الحقوللا تُتاح عادةً405 + Allowتغيير الحقول المرسلة فقط200 أو 204
DELETEالحذفلا تُتاح عادةً405 + Allowحذف المهمة204 (أو 200 أو 202) · ثم يعيد GET الرمز 404
  • عملية CRUD ورمز نجاحها المعتاد
  • غير متاحة: توقّع 405 Method Not Allowed مع ترويسة Allow

تصميم معتاد: عقد الواجهة نفسها هو الذي يحدد التركيبات المتاحة.

النسخة النصية
Operation  Method  URI          Typical success response
---------  ------  -----------  ---------------------------------------------
Create     POST    /tasks       201 Created + Location: /tasks/{id}
Read       GET     /tasks       200 OK, a list (often paged)
Read       GET     /tasks/{id}  200 OK, one task
Update     PUT     /tasks/{id}  200 OK or 204 No Content, whole task replaced
Update     PATCH   /tasks/{id}  200 OK or 204 No Content, sent fields only
Delete     DELETE  /tasks/{id}  204 No Content (200 with a body, 202 if queued)

رموز الحالة في واجهة REST

يتفرّع سلوك العملاء بحسب رمز الحالة قبل قراءة الجسم، ولذلك فالرمز جزء من العقد. وفي REST ينتج الرمز عن العملية وعن حالة المورد، فتستطيع كل حالة اختبار أن تذكر الرمز المتوقع.

  • 201 Created بعد الإنشاء، مع ترويسة Location تحمل عنوان المورد الجديد (RFC 9110). وإعادة 200 مع المعرّف في الجسم فقط انحراف شائع، والعقد هو الذي يحدد هل هو عيب.
  • 204 No Content لتحديث أو حذف ناجح لا يعيد شيئاً: يجب أن يكون الجسم فارغاً.
  • 404 Not Found لعنصر غير موجود، ومنه العنصر المحذوف للتو. أما القائمة الفارغة فهي 200 مع مصفوفة فارغة.
  • 405 Method Not Allowed لطريقة لا يدعمها المورد، مع ترويسة Allow تذكر الطرق التي يدعمها؛ وهذه الترويسة يشترطها RFC 9110.
  • 415 Unsupported Media Type لجسم بصيغة لا يقبلها المورد؛ و406 Not Acceptable حين لا يستطيع الخادم إنتاج أيٍّ من الصيغ المذكورة في Accept، مع أن RFC 9110 يسمح له أيضاً بإرسال صيغته الافتراضية بدلاً من ذلك.
  • 409 Conflict حين يتعارض الطلب مع الحالة الحالية، مثل بريد إلكتروني مسجّل مسبقاً؛ و400 أو 422 للمدخلات غير الصالحة، باستخدام متسق.
  • لا 5xx أبداً لخطأ من العميل: فالرمز 500 لمدخلات سيئة يعني غالباً أن التحقق من صحة المدخلات أو معالجة الأخطاء مفقودة.

جرّبها: محلّل رموز حالة HTTP جرّبها: مرجع رموز حالة HTTP

مثال تطبيقي: مهمة واحدة عبر دورة حياتها

يمرّر المختبِر مهمة واحدة عبر كل العمليات، ويتحقق بعد كل خطوة من رمز الحالة ومن الحالة المخزنة. ويبدأ حساب الاختبار دون أي مهام.

  • تستخدم الخطوات اللاحقة /v1/tasks/57 المأخوذ من ترويسة Location بدلاً من عنوان مخمَّن.
  • الطريقة POST تخص المجموعة: فعلى العنصر /v1/tasks/57 تُقابَل بالرمز 405، وتذكر ترويسة Allow الطرق التي يدعمها العنصر فعلاً.
  • بعد الحذف يختفي العنصر، فيعيد GET /v1/tasks/57 الرمز 404؛ أما المجموعة فما زالت موجودة، فيعيد GET /v1/tasks الرمز 200 مع مصفوفة فارغة، لا 404.
  • وتبقى لكل طريقة وعودها الخاصة هنا أيضاً — فـPATCH يغيّر الحقول المرسلة فقط، وPUT يحمل الحالة الكاملة، وطلب DELETE المكرر قد يعيد 404 ويبقى متكافئاً — كما يشرح قسما الطرق الآمنة والمتكافئة وما تختبره في كل طريقة في درس طرق HTTP.
POST /v1/tasks  {"title": "Pay rent", "done": false}
  -> 201 Created, Location: /v1/tasks/57
GET /v1/tasks/57
  -> 200 OK, {"id": 57, "title": "Pay rent", "done": false}
PATCH /v1/tasks/57  {"done": true}
  -> 200 OK, {"id": 57, "title": "Pay rent", "done": true}
POST /v1/tasks/57
  -> 405 Method Not Allowed, Allow: GET, HEAD, PUT, PATCH, DELETE
DELETE /v1/tasks/57
  -> 204 No Content
GET /v1/tasks/57
  -> 404 Not Found
GET /v1/tasks
  -> 200 OK, []

جرّبها: مختبِر REST API جرّبها: منشئ طلبات API

إدارة الإصدارات والتغييرات الكاسرة

للواجهة عملاء لا يتحكم فيهم فريقها، فلا يستطيع تغييرها بحرية. والتغيير الكاسر (Breaking Change) هو ما يجعل عميلاً سليماً لم يتغير يتعطّل: حذف حقل أو إعادة تسميته، أو تغيير نوعه، أو جعل حقل اختياري في الطلب إلزامياً، أو تغيير عنوان URI أو رمز حالة. أما إضافة نقطة نهاية أو حقل اختياري فآمنة عادةً، بشرط أن يتجاهل العملاء الحقول التي لا يعرفونها.

لا يفرض REST نظاماً لإدارة الإصدارات (Versioning). تختار الفرق نظاماً وتوثّقه في العقد، وغالباً ما يكون مستند OpenAPI: مسار URI (/v1/tasks)، أو معامل استعلام (?version=2)، أو ترويسة طلب مخصصة مثل Api-Version: 2 (ويختلف اسمها من واجهة لأخرى)، أو نوع الوسائط (Accept: application/vnd.example.v2+json).

  • بعد إطلاق نسخة جديدة، شغّل اختبارات الانحدار للنسخة القديمة دون تعديل: يجب أن تبقى v1 تتصرف كما ينص عقدها.
  • أرسل الطلب نفسه إلى النسختين، وتأكد من أن الفروق الظاهرة هي الفروق الموثّقة فقط.
  • أرسل طلباً بلا نسخة، وبنسخة مجهولة، وبنسخة أُوقف العمل بها: توقّع السلوك الافتراضي الموثّق أو خطأ 4xx واضحاً، لا 500 أبداً.

جرّبها: مقارنة استجابات API جرّبها: عارض OpenAPI

أخطاء شائعة

  • التعامل مع REST كمعيار بقواعد ثابتة. إنه أسلوب معماري، وعقد الواجهة هو الذي يحدد التفاصيل.
  • اختبار الطلبات بالترتيب الذي ترسلها به واجهة المستخدم فقط. فطلب REST عديم الحالة، لذا أرسله منفرداً أيضاً: الصفحة ⁦3⁩ دون الصفحتين ⁦1⁩ و⁦2⁩، والعنصر بعنوانه دون تحميل القائمة.
  • قبول أي 2xx نجاحاً مع أن العملاء يعتمدون على الرمز الدقيق، مثل 201 مع Location.
  • توقّع 404 لقائمة فارغة. فالمجموعة ما زالت موجودة، والإجابة الصحيحة 200 مع مصفوفة فارغة؛ أما 404 فللعنصر غير الموجود.
  • اختبار أحدث نسخة فقط بعد الإصدار، وتفويت تغيير تسرّب إلى v1.

من منظور ضمان الجودة

تظهر قيمة معرفة REST قبل تشغيل أي شيفرة. راجع العقد الجديد أو المعدّل كما تراجع المتطلبات: لكل مورد، ما الطرق المتاحة، وما رمز الحالة لكل منها، وماذا يحدث عند التكرار أو غياب العنصر، وهل التغيير كاسر. واتفق على الإجابات مع المطورين ومع الفرق التي تستهلك الواجهة — الويب والجوال والشركاء.

اكتب رمز الحالة المتوقع وأهم الترويسات في كل حالة اختبار، واحتفظ باختبار دورة حياة واحد لكل مورد. وفي تقرير الخطأ اذكر الطريقة وعنوان URI وجسم الطلب ورمز الحالة المتوقع والفعلي، ليعيد المطور تنفيذ الطلب في ثوانٍ.

تمرين عملي

راجع سجل واجهة حجز مواعيد في عيادة

المطلوب

تختبر مورد المواعيد في واجهة لحجز مواعيد عيادة على بيئة Staging. يعرّف العقد /v1/appointments و/v1/appointments/{id}، ويوثّق 201 Created مع ترويسة Location عند الإنشاء وتصفية القائمة بالمعامل date، ويعيد 404 للعناصر غير الموجودة. قرّر، سطراً سطراً، هل كل استجابة مرصودة صحيحة؛ ولكل استجابة خاطئة اذكر الاستجابة المتوقعة وسببها.

المادة
#  Request                                            Observed response
1  POST   /v1/appointments  (valid JSON body)         200 OK, body has "id": 381,
                                                      no Location header
2  GET    /v1/appointments?date=2026-11-02            404 Not Found,
                                                      no appointments on that date
3  POST   /v1/appointments/381                        404 Not Found
4  POST   /v1/appointments  Content-Type: text/plain  500 Internal Server Error
5  DELETE /v1/appointments/381                        204 No Content
6  GET    /v1/appointments/381                        404 Not Found
7  DELETE /v1/appointments/381                        500 Internal Server Error
8  GET    /v1/appointments/377  (after v2 release)    "time" is now named "startsAt"
الخطوات
  1. اكتب رمز الحالة المتوقع (والترويسة حين تهم) انطلاقاً من الطريقة وعنوان URI وحالة المورد في تلك اللحظة.
  2. قارنه بالاستجابة المرصودة، وصنّف السطر: ناجح أو عيب.
  3. رتّب العيوب بحسب أثرها على العملاء والمستخدمين.
إظهار الإجابة النموذجية
الإجابة النموذجية

الصحيح: السطران ⁦5⁩ و⁦6⁩. فبعد الحذف يكون 404 هو المطلوب تماماً.

السطر ⁦1⁩: المتوقع 201 Created مع Location: /v1/appointments/381 كما يوثّق العقد. والعملاء الذين يقرؤون العنوان الجديد من Location لا يستطيعون المتابعة.

السطر ⁦2⁩: المجموعة موجودة حتى إن لم يطابق أي موعد المرشِّح (Filter)، فالمتوقع 200 OK مع مصفوفة فارغة. أما 404 فيخبر العملاء بأن القائمة نفسها غير موجودة، وكثير منهم سيعرض رسالة خطأ بدلاً من يوم بلا مواعيد.

السطر ⁦3⁩: الطريقة POST تخص المجموعة /v1/appointments لا العنصر، والموعد ⁦381⁩ موجود، فالرمز 404 مضلّل؛ والمتوقع 405 Method Not Allowed مع ترويسة Allow تذكر الطرق التي يدعمها العنصر.

السطر ⁦4⁩: صيغة الجسم غير المدعومة خطأ من العميل؛ والمتوقع 415 Unsupported Media Type لا انهيار الخادم.

السطر ⁦7⁩: الموعد محذوف مسبقاً، فالمتوقع 404 كما ينص العقد للعناصر غير الموجودة. و500 حالة غير معالَجة؛ تأكد بطلب GET أن الحالة لم تتغير.

السطر ⁦8⁩: تغيير كاسر تسرّب إلى v1. فإعادة التسمية مكانها v2 وحدها.

أبلغ أولاً عن السطر ⁦8⁩ (يعطّل العملاء الحاليين)؛ ثم السطرين ⁦4⁩ و⁦7⁩ (500 حيث يُتوقع 4xx)؛ ثم الأسطر ⁦1⁩ و⁦2⁩ و⁦3⁩ (رموز مضلّلة).

أسئلة شائعة

هل REST هو HTTP نفسه؟

لا. HTTP بروتوكول تعرّفه معايير IETF مثل RFC 9110، أما REST فأسلوب معماري. تعمل واجهات REST عادةً فوق HTTP، لكن واجهة HTTP قد تتجاهل REST كلياً، كأن ترسل كل إجراء بطلب POST إلى عنوان واحد.

هل يعيد الإنشاء 200 أم 201؟

ينص RFC 9110 على أنه حين ينشئ POST مورداً، ينبغي أن يرسل الخادم 201 Created مع ترويسة Location تحدّد المورد. وبعض الواجهات تعيد 200 مع المعرّف الجديد في الجسم؛ وهذا يعمل فقط إن نص عليه العقد وتوقعه كل العملاء. اختبر وفق العقد، وأبلغ عن ذلك حين تختلف نقاط نهاية الواجهة نفسها في ذلك.

كيف تقسّم واجهة REST قائمة طويلة إلى صفحات (Pagination)؟

لا يفرض REST نظاماً لذلك، فيجب أن يحدده العقد. ومن التصاميم الشائعة معاملات رقم الصفحة أو الإزاحة (Offset) مثل ?page=3&size=20، ومؤشر (Cursor) مُعتم تعيده كل استجابة لاستخدامه في الطلب التالي؛ وبعض الواجهات تعيد أيضاً عنوان URI للصفحة التالية، في الجسم أو في ترويسة Link. اختبر الصفحة الأولى والأخيرة، وصفحة بعد النهاية (200 مع مصفوفة فارغة، أو خطأ 4xx الموثّق)، وأكبر حجم صفحة مسموح وما يزيد عليه بواحد، وتأكد من أن أي عنصر لا يُتخطّى ولا يتكرر حين تُضاف عناصر بين الطلبات، وهو ضعف معروف في الترقيم بالإزاحة.

أي نظام لإدارة الإصدارات هو الأفضل؟

لا توجد إجابة معيارية. وضع النسخة في مسار URI سهل الرؤية والتوجيه والاختبار، وإدارة الإصدارات بالترويسة أو بنوع الوسائط تُبقي عناوين URI ثابتة. والمهم للاختبار أن يكون النظام موثّقاً، ومطبّقاً بالطريقة نفسها على كل نقاط النهاية، وأن تبقى النسخ القديمة تعمل حتى موعد إيقافها المعلن.

المراجع

  • RFC 9110: HTTP SemanticsIETF · 2022معاني أساليب HTTP وحقول الترويسات ورموز الحالة والتفاوض على المحتوى، بغضّ النظر عن إصدار البروتوكول.
  • RFC 3986: Uniform Resource Identifier (URI): Generic SyntaxIETF · 2005أجزاء URI (النظام والسلطة والمسار والاستعلام والجزء) والمحارف المحجوزة والترميز بالنسبة المئوية.
  • RFC 5789: PATCH Method for HTTPIETF · 2010أسلوب PATCH للتحديثات الجزئية، مقابل PUT الذي يستبدل المورد كاملاً.
  • OpenAPI SpecificationOpenAPI Initiativeالمعيار لوصف واجهات REST: المسارات والعمليات والمعاملات والمخططات والاستجابات وأنظمة الأمان.

تدرّب بأدوات متقن

اختبر نقاط نهاية REST بتحكم كامل في الطريقة والترويسات وجسم JSON، ثم أضف تأكيدات على الحالة والترويسات ومسارات JSON.

اختبار واجهات API

أنشئ طلبات HTTP وأرسلها (الطريقة وعنوان URL والترويسات والمصادقة والجسم) وافحص الاستجابة — بديل خفيف لـ Postman داخل متصفحك.

اختبار واجهات API

تحليل رمز حالة HTTP وترويسات الاستجابة، مع شرح يبيّن ما إذا كان الرمز صحيحاً في هذا الموقف.

التحقق

ابحث عن أي رمز حالة HTTP لمعرفة معناه ومرجعه في RFC ومتى يُستخدم.

الويب

قارن استجابتي API (مثل بيئة التجريب مقابل الإنتاج) واحصل على قائمة بكل فرق بنيوي أو في القيم.

اختبار واجهات API

عرض مواصفة OpenAPI 3.x / Swagger 2.0 (بصيغة JSON أو YAML) كتوثيق قابل للتصفح لنقاط النهاية.

الويب

للتعمّق أكثر

تقدّمك في هذا الموضوع

جزء من مسار تعلم ضمان الجودة