مبادئ REST و @RestController
مبادئ REST و @RestController
قبل كتابة أي تعليق توضيحي (annotation)، يستحق الأمر أن تفهم ما هو REST فعلًا ولماذا أصبح الأسلوب السائد لواجهات برمجية على الويب. REST (نقل الحالة التمثيلية) هو أسلوب معماري وليس بروتوكولًا أو معيارًا. عرّفه روي فيلدينج في أطروحته الدكتورية عام 2000 بوصفه مجموعة من القيود التي، حين تُطبَّق على نظام موزّع، تُنتج خصائص مرغوبة: قابلية التوسع، والانعدام الحالة، وواجهات موحّدة، وسهولة التطور.
يوفّر Spring Boot 3 و Spring 6 أدوات من الدرجة الأولى لبناء REST APIs، لكن الإطار لا يستطيع فرض دلالات REST بنفسه — إذ يكتفي بتسهيل ربط أفعال HTTP والمسارات والتسلسل معًا. معرفة المبادئ هي التي تجعلك تُصمّم APIs تتحمّل الزمن بدلًا من تلك التي تتراكم عليها الحلول المؤقتة.
القيود الست لـ REST
تسرد أطروحة فيلدينج الأصلية ست قيود. ثلاث منها أساسية في التصميم اليومي للـ API:
- الواجهة الموحّدة. يتفاعل العملاء والخوادم من خلال واجهة متسقة — موارد مُعرَّفة بعناوين URI، تُعالَج عبر تمثيلات، ورسائل ذاتية الوصف وروابط hypermedia. في REST المبني على HTTP يعني هذا: استخدام الأسماء لمسارات الموارد (
/orders/42لا/getOrder?id=42)، وفعل HTTP للتعبير عن العملية، وإعادة رموز حالة ذات معنى. - انعدام الحالة. يجب أن يحتوي كل طلب على جميع المعلومات اللازمة لمعالجته. لا يخزّن الخادم أي حالة جلسة بين الطلبات. لهذا تُفضّل REST APIs الرموز المميزة في الترويسات (
Authorization: Bearer …) على جلسات جانب الخادم — أي نسخة في مجموعة عناقيد يمكنها معالجة أي طلب. - فصل العميل عن الخادم. يُدير العميل واجهة المستخدم؛ ويُدير الخادم البيانات ومنطق الأعمال. يتطوّران باستقلالية طالما أن عقد الـ API صامد. هذه هي الحدود التي يجلس عندها
@RestController.
القيود الثلاثة الباقية (التخزين المؤقت، والنظام المتعدد الطبقات، والكود عند الطلب) مهمة في نطاق واسع لكنها أقل صلةً عند هيكلة المتحكّمات لأول مرة.
الموارد والتمثيلات وأفعال HTTP
المورد هو أي مفهوم مُسمًّى تعرضه الـ API: منتج، أو طلب، أو مستخدم، أو تقرير. تُعرَّف الموارد بعناوين URI. التمثيل هو الحالة الراهنة لذلك المورد مُسلسَلةً في تنسيق يمكن للعميل استهلاكه — عادةً JSON، وأحيانًا XML أو CSV.
تحمل أفعال HTTP النية:
- GET — استرجاع تمثيل؛ يجب أن يكون آمنًا (لا آثار جانبية) وعديم التأثير المتكرر (idempotent).
- POST — إنشاء مورد فرعي جديد أو تشغيل إجراء؛ لا آمن ولا عديم التأثير المتكرر.
- PUT — استبدال مورد كاملًا؛ عديم التأثير المتكرر (استدعاؤه مرتين له نفس نتيجة استدعائه مرة).
- PATCH — تحديث جزئي؛ ليس بالضرورة عديم التأثير المتكرر.
- DELETE — حذف المورد؛ عديم التأثير المتكرر.
الـ Stereotype الخاص بـ @RestController
في تطبيق Spring MVC، يُميّز @Controller فئةً باعتبارها مكوّنًا في طبقة الويب ويتوقع افتراضيًا أن تُعيد توابعه أسماء views. إضافة @ResponseBody إلى تابع يأمر Spring بكتابة القيمة المُعادة مباشرةً في جسم استجابة HTTP بدلًا من حل view.
@RestController هو تعليق توضيحي مُركّب — يجمع حرفيًا @Controller + @ResponseBody على مستوى الفئة. كل تابع معالج في الفئة يحمل ضمنيًا @ResponseBody. هذا هو الفرق الوحيد. تنتهي سلسلة التعليقات إلى bean مُدار من Spring في سياق التطبيق، مؤهّل لحقن التبعية وأجهزة AOP وبنية التوجيه في dispatcher servlet.
عندما تكتشف الإعدادات التلقائية في Spring Boot وجود spring-boot-starter-web في classpath، تُسجّل Jackson (MappingJackson2HttpMessageConverter) كمحوّل رسائل افتراضي. يُسلسل Jackson الـ List<ProductDto> إلى JSON تلقائيًا — لا تحتاج أبدًا لكتابة كود ObjectMapper يدويًا في المتحكّم.
كيف تعمل دورة الطلب-الاستجابة
فهم المسار من طلب HTTP الوارد إلى استجابة JSON يمنحك حدسًا أفضل في التصحيح:
- يتلقّى حاوية Tomcat المُضمَّنة اتصال TCP ويحلّل طلب HTTP.
- يستشير
DispatcherServlet— المتحكّم الأمامي لـ Spring MVC — سجلHandlerMappingالخاص به ليجد أي تابع متحكّم يعالج تركيبة هذا URI وفعل HTTP. - يُستدعى التابع. تُحلّ معاملاته (متغيرات المسار، معاملات الاستعلام، جسم الطلب) باستخدام
HandlerMethodArgumentResolvers المُسجَّلة. - تُعالَج قيمة الإعادة بواسطة
HandlerMethodReturnValueHandler. بما أن@ResponseBodyموجود، تُمرَّر القيمة إلىHttpMessageConverterالمُتفاوَض عليه (Jackson لـ JSON) الذي يكتب البايتات في مجرى إخراج الاستجابة. - تُرسل Tomcat الاستجابة إلى العميل.
مثال متكامل ومختصر
فيما يلي مثال كامل باستخدام Spring Boot 3 مع استيرادات jakarta.*. يوضح هيكل الحزم، ونموذج DTO بسيط باستخدام Record، وحدود الخدمة، والمتحكّم المُوصَّل معًا.
بهذا الهيكل، يكتشف Spring Boot كلا الـ bean تلقائيًا (فحص المكوّنات)، ويُوصّل الخدمة في المتحكّم، ويعيّن طلبات GET. تسلسل حقول السجل إلى JSON يتم تلقائيًا.
@Entity من تابع @RestController يُسرّب مخطط قاعدة البيانات، وقد يُطلق استثناءات التحميل الكسول، ويُصعّب تطوير الـ API باستقلالية عن نموذج البيانات. حدّد دائمًا طبقة DTO — السجلات خيار ممتاز في Java 16 فما فوق.
الخلاصة
REST أسلوب معماري مبني على واجهات موحّدة، وانعدام حالة، وعناوين URI موجّهة بالموارد. تحمل أفعال HTTP دلالة النية — GET و POST و PUT و PATCH و DELETE — وتحدد خاصية idempotency أمان إعادة المحاولة. @RestController stereotype مُركَّب يُميّز الفئة باعتبارها متحكّمًا مُدارًا من Spring وكاتبًا مباشرًا لجسم الاستجابة في آنٍ واحد، مما يُلغي الحاجة لـ @ResponseBody على كل تابع. يتكامل Jackson تلقائيًا عبر الإعداد التلقائي لـ Spring Boot. أبقِ المتحكّمات رفيعة: استقبل الطلب، فوّض، أعِد الاستجابة. الدرس التالي يتناول تعيين الطلبات بالتفصيل — كيف توجّه أفعال HTTP المختلفة وأنماط المسارات إلى توابع معالجة محددة.