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

المُزخرِفات المخصّصة

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

المُزخرِفات المخصّصة

استخدمت مُزخرِفات كثيرة — @Get() و@Body() و@UseGuards(). يتيح لك NestJS بناء مُزخرِفاتك، فتصبح المتحكّمات أنظف والمقصد أوضح. يغطّي هذا الدرس مُزخرِفات المعاملات ومُزخرِفات البيانات الوصفية ودمجها — ويجمع دورة حياة الطلب كاملةً.

مُزخرِفات المعاملات المخصّصة

الوصول إلى الطلب لجلب القيمة نفسها في كل معالج تكرار مُملّ. يستخرجها مُزخرِف معامل مخصّص مرّة واحدة، تصريحيًّا. المثال الكلاسيكي مُزخرِف @User() يسحب المستخدم المُصادَق من الطلب:

import { createParamDecorator, ExecutionContext } from '@nestjs/common'; export const User = createParamDecorator( (data: string, ctx: ExecutionContext) => { const request = ctx.switchToHttp().getRequest(); return data ? request.user?.[data] : request.user; }, );

الآن يقرأ أي معالج المستخدم بمعامل نظيف ذاتي الوصف:

@Get('profile') getProfile(@User() user: UserEntity) { return user; } @Get('email') getEmail(@User('email') email: string) { // data = 'email' return email; }
وسيط data هو ما تمرّره إلى المُزخرِف — فـ @User('email') يمرّر 'email' كـ data. وهذا يتيح لمُزخرِف واحد إعادة الكائن كاملًا أو حقلًا واحدًا.

مُزخرِفات البيانات الوصفية

قابلت @SetMetadata() مع الحُرّاس. تغليفها في مُزخرِف مُسمّى يجعل المقصد واضحًا ويتفادى النصوص السحرية المبعثرة في الكود:

import { SetMetadata } from '@nestjs/common'; export const Roles = (...roles: string[]) => SetMetadata('roles', roles); // الاستخدام — أوضح بكثير من @SetMetadata('roles', ['admin']) @Roles('admin') @Get('reports') getReports() {}

يقرأه الحارس المطابق بـ reflector.get('roles', context.getHandler())، تمامًا كما في درس الحُرّاس.

تركيب المُزخرِفات

تَحزِم applyDecorators() عدّة مُزخرِفات في مُزخرِف واحد قابل لإعادة الاستخدام — رائعة لتركيبة شائعة كـ "يتطلّب مصادقة + دورًا + توثيق Swagger":

import { applyDecorators, UseGuards } from '@nestjs/common'; export function Auth(...roles: string[]) { return applyDecorators( Roles(...roles), UseGuards(AuthGuard, RolesGuard), ); } // مُزخرِف واحد يفعل كل شيء @Auth('admin') @Get('reports') getReports() {}

دورة حياة الطلب كاملةً

بعد أن قابلت كل لبنة، هذا ترتيب تدفّق كل طلب:

Request -> Middleware (الوسيطات) -> Guards (الحُرّاس) -> Interceptors (المعترِضات — قبل المعالج) -> Pipes (الأنابيب) -> Route Handler (دالّة متحكّمك) -> Interceptors (المعترِضات — بعد المعالج) -> Exception Filters (مرشّحات الاستثناءات — فقط إن رُمي خطأ) -> Response
معرفة هذا الترتيب هي ما يجعلك طليقًا في NestJS. حين تسأل "أين يجب أن يذهب هذا المنطق؟"، الجواب غالبًا "في المرحلة ذات السياق الصحيح" — المصادقة في الحُرّاس، والتحويل في الأنابيب/المعترِضات، والأخطاء في المرشّحات.

الخلاصة

تجعل المُزخرِفات المخصّصة المتحكّمات مُعبّرة: تستخرج createParamDecorator بيانات الطلب (مثل @User())، وتُرفِق أغلفة SetMetadata (مثل @Roles()) بياناتٍ وصفية للحُرّاس، وتُركّب applyDecorators عدّةً في واحد. وبعد أن اتّضحت دورة الحياة كاملةً — الوسيطات والحُرّاس والمعترِضات والأنابيب والمعالج والمرشّحات — أكملت المرحلة الثالثة وتستطيع بناء معالجة طلبات NestJS متينة ومُهيكَلة جيدًا.