Spring Boot / الأساسي: التركيب وعقود HTTP / الدرس 4
متحكمات HTTP وعقود الاستجابة
كيّف إدخال HTTP لاستدعاء التطبيق وحول النتائج الصريحة إلى طرائق وحالات وترويسات و DTO مستقرة.
في هذه الصفحة
أهداف الدرس
- فصل المسار من سلوك المجال.
- تمييز فشل الربط وغياب المورد ورفض العملية.
- تعريف التمثيل دون كشف داخل الاستمرارية.
المتحكم محول وليس التطبيق كله
يمر طلب Servlet بالمرشحات والربط والتحويل والاستدعاء والاستجابة. يترجم المتحكم النقل ويفوض سياسة المجال، ولا يملك كل قرار قاعدة أو أمان. تجمع @RestController الاكتشاف وإرجاع الجسم، ولا تجعل كل حقل آمناً للتسلسل أو تثبت حق الطالب في المعرف.
اختر الطريقة وفق عقد: تجلب GET تمثيلاً دون طلب تعديل عمل، وتقدم POST إنشاءً أو عملاً، وتختلف PUT و PATCH و DELETE. لا تعني دلالة التكرار غياب التسجيل أو أمان إعادة كل أثر خارجي فاشل؛ فتحتاج هوية العمل الحساسة للإعادة تصميماً إضافياً سنطوره لاحقاً.
حوّل نتائج التطبيق المحددة النوع صراحة
يربط الجزء /products/{id} بقدرة بحث ويعيد 200 أو 404 وفق Optional، ويحتاج عقد ProductService وكائنه المُدار. لم ينفذ كنقطة شبكة. قد يفشل المسار العددي التالف قبل الدالة، بينما يسلك المعرف الصحيح الغائب مسار نتيجة مختلفاً.
يحتاج الوصول هوية ونطاقاً موثوقين وسياسة إفصاح متسقة للغائب والممنوع. قد يكون 404 قرار إخفاء مقصوداً لكنه لا يعوض فحص الحق. أظهر الحالات في عقد التطبيق ولا تعِد null لتقرر معالجة عرضية معنى النتيجة التجارية نيابة عنك.
package training.catalog;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
record ProductView(long id, String name) {}
@RestController
@RequestMapping("/products")
class ProductController {
private final ProductService products;
ProductController(ProductService products) { this.products = products; }
@GetMapping("/{id}")
ResponseEntity<ProductView> find(@PathVariable long id) {
return products.find(id).map(ResponseEntity::ok)
.orElseGet(() -> ResponseEntity.notFound().build());
}
}
الخدمة قدرة سياقية تعيد Optional؛ ولم ينفذ المسار أو المرشح أو التسلسل.
اكتب ملف عقد مقصود للطلب والاستجابة
يعرض مقطع HTTP تبادلاً مصطنعاً مقصوداً لمنتج معروف مخول: المسار و Accept و Content-Type والحالة والحقول. ليس رداً ملتقطاً، ويبقى غير قابل للتشغيل. يمكن لـ MockMvc فحص العقد دون مستمع، مع اختبارات أخرى للمرشحات والحد الكامل واعتماديات مضبوطة.
اكشف في DTO الحقول المعتمدة فقط؛ فقد يسرب تسلسل الكيان الداخل أو يعبر علاقات كسولة أو ينشئ دورة أو قراءة إضافية. حدد الاسم والوحدة والوقت والغياب وترتيب المجموعة. لا يثبت JSON صحيح وحده صحة المعنى أو الحالة المختارة.
GET /products/42 HTTP/1.1
Accept: application/json
HTTP/1.1 200 OK
Content-Type: application/json
{"id":42,"name":"Training notebook"}
يحدد ملف العقد النجاح المختار، وتحتاج حالات الغياب والمنع والربط فحوصاً مستقلة.
اجعل الحالة والترويسات جزءاً من المعنى
تعبر 400 عن إدخال غير صالح وفق العقد، و 401 و 403 عن حدود المصادقة والتفويض، و 404 عن الغياب أو الإخفاء المختار، وقد تمثل 409 تعارض حالة محدداً. ليست 500 بديلاً لكل رفض تجاري، ولا تعِد 200 بجسم خطأ غير موثق. حدد نجاح الإنشاء و Location عند انطباقهما.
تصف Content-Type المرسل، وتحدد Accept المطلوب للاستجابة؛ وقد يفشلان في مرحلتين مختلفتين. تدعم ETag أوحقل النسخة عقد تزامن متفائل إذا قارنت وعدلت فعلاً. لا يحمي وجود الترويسة وحده من ضياع التحديثات.
اختبر المحول بحالات دقيقة
اختبر المسار الصحيح والغائب والتحويل التالف والمورد المفقود والمخول والمنع والوسائط والحقول. ميّز التحقق ورفض المجال وفشل البنية. لا يثبت استدعاء الدالة مباشرة ربط MVC أو الأمان؛ فهو يتجاوز المرشحات والمحللات والتحويل والنصيحة.
اختر شريحة ويب أو اختباراً وهمياً مناسباً وأبق وحدة منفصلة للسياسة. استخدم هويات مصطنعة دون اعتماد حقيقي. يسهل صيانة المتحكم حين يفسر المسار والمدخل والاستدعاء والخرج مستقلين، دون تعديل قاعدة خفي في مسار يفترض أنه قراءة فقط.
الأخطاء الشائعة وإصلاحها
فات اختبار مباشر فشل ربط.
- لماذا يحدث؟
- تجاوز تحويل معاملات MVC.
- كيف تصلحه؟
- استخدم اختبار MVC وهمياً مناسباً.
- كيف تتجنب تكراره؟
- افصل دليل الوحدة والويب.
كشف الرد حقول استمرارية داخلية.
- لماذا يحدث؟
- صار الكيان تمثيلاً عاماً دون مراجعة.
- كيف تصلحه؟
- حوّل DTO معتمدة وافحص الحقول.
- كيف تتجنب تكراره؟
- راجع التسلسل والعلاقات الكسولة.
صار كل رفض 500.
- لماذا يحدث؟
- غاب تحويل نتائج المجال والإدخال.
- كيف تصلحه؟
- حدد حالة وخطأ ثابتين لكل حد.
- كيف تتجنب تكراره؟
- اختبر مسارات الرفض.
اختبر فهمك
1. لماذا لا يثبت find(42) المباشر أمان GET وتسلسله؟
اعرض الحل المشروح
يتجاوز المسار والمرشح والهوية والربط والتحويل والنصيحة، فيفحص التفويض البرمجي فقط. أضف اختبار إطار محدوداً ببيانات وضبط مصطنعين.
2. ما الذي ينقص price:12 في الرد؟
اعرض الحل المشروح
العملة والمقياس والدقة والغياب وهل هو سعر وحدة أو مجموع. لا يكفي رقم JSON وحالة 200 للمعنى؛ اختر التمثيل وافحص العقد.
أهم ما تعلمته
- يكيف المتحكم النقل ويفوض السياسة.
- الحالة والترويسة والشكل والتفويض عقود صريحة.
- ملف HTTP المصطنع قصد لا استجابة ملتقطة.