NestJS — Node.js للمؤسسات

المعترِضات (Interceptors)

17 دقيقة الدرس 14 من 30

المعترِضات (Interceptors)

يُغلّف المعترِض (interceptor) المعالجَ، مشغّلًا منطقًا قبله وبعده. مستوحاةً من البرمجة الموجَّهة بالجوانب، المعترِضات مثاليّة للسلوك العابر الذي لا تريد تكراره في كل معالج: تحويل الاستجابات، وتسجيل الأزمنة، والتخزين المؤقت، وإضافة المهل.

واجهة NestInterceptor

يُنفّذ المعترِض intercept(context, next). والمفتاح هو next.handle(): استدعاؤه يشغّل معالج المسار ويُعيد Observable من RxJS للاستجابة. تُضيف عوامل إلى ذلك التدفّق للتصرّف بعد المعالج:

import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common'; import { Observable } from 'rxjs'; import { tap } from 'rxjs/operators'; @Injectable() export class LoggingInterceptor implements NestInterceptor { intercept(context: ExecutionContext, next: CallHandler): Observable<any> { const now = Date.now(); // الكود هنا يعمل قبل المعالج return next .handle() .pipe(tap(() => console.log(`Took ${Date.now() - now}ms`))); // الكود في .pipe() يعمل بعد المعالج } }

تحويل الاستجابة

استخدام كلاسيكي هو تغليف كل استجابة في مظروف موحّد باستخدام عامل map:

import { map } from 'rxjs/operators'; @Injectable() export class TransformInterceptor implements NestInterceptor { intercept(context: ExecutionContext, next: CallHandler): Observable<any> { return next.handle().pipe( map((data) => ({ success: true, data })), ); } } // يُعيد المعالج { id: 1 } -> يستلم العميل { success: true, data: { id: 1 } }

قبل وبعد، في مكان واحد

لأنّ المنطق قبل next.handle() وداخل .pipe() يقعان في الدالّة نفسها، يستطيع المعترِض قياس المدّة، أو تعديل النتيجة، أو التقاط الأخطاء، أو الاختصار بقيمة مخزّنة — كلّه دون لمس المعالج.

أنماط المعترِضات الشائعة

  • تشكيل الاستجابة — تغليف البيانات في بنية موحّدة (بـ map).
  • التسجيل/التوقيت — تسجيل مدّة كل طلب (بـ tap).
  • التخزين المؤقت — إعادة قيمة مخزّنة وتخطّي المعالج كلّيًا.
  • المهل — إفشال طلب يطول أكثر من اللازم (بعامل timeout).
  • التسلسل — إزالة الحقول الحسّاسة (مثل ClassSerializerInterceptor).

تطبيق المعترِضات

import { UseInterceptors } from '@nestjs/common'; @UseInterceptors(LoggingInterceptor) // مستوى الدالّة أو المتحكّم @Get() findAll() {} // أو عامًّا: app.useGlobalInterceptors(new TransformInterceptor());
المعترِضات ترى الاستجابة؛ الحُرّاس لا. يعمل الحارس قبل المعالج ويسمح/يمنع فقط. أمّا المعترِض فيعمل حول المعالج ويستطيع قراءة وإعادة تشكيل ما يُعيده — تلك المرحلة "بعد" هي الفرق.
المعترِضات مبنيّة على RxJS. تصبح قيمة المعالج المُعادة Observable. إن كنت غير معتاد على عوامل كـ map وtap، ابدأ بهذين — فهما يغطّيان معظم المعترِضات الواقعية.

الخلاصة

تُغلّف المعترِضات المعالج بمنطق قبل/بعد عبر intercept(context, next). استدعاء next.handle() يشغّل المعالج ويُعيد Observable تُحوّله بعوامل RxJS كـ map (إعادة تشكيل) وtap (آثار جانبية). استخدمها لمظاريف الاستجابة والتسجيل والتخزين المؤقت والمهل، مُطبَّقةً بـ @UseInterceptors(). تاليًا: مرشّحات الاستثناءات، التي تتحكّم بما يحدث عند الخطأ.