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

تعمّق في حقن التبعيات

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

تعمّق في حقن التبعيات

لقد استخدمت حقن التبعيات سلفًا — بإعلان خدمة في الباني وترك NestJS يزوّدها. والآن لنفتح الصندوق. فهمُ حاوي IoC ورموز المزوّدات (tokens) يحوّل الحقن من سحر إلى أداة تتحكّم بها كاملًا.

حاوي IoC

IoC تعني عكس التحكّم. بدل أن تُنشئ أصنافك تبعياتها بنفسها، يُنشئها ويزوّدها حاوٍ مركزي. عند الإقلاع، يمسح NestJS كل وحدة، ويبني خريطة للمزوّدات، ثم يُنشئها بالترتيب الصحيح، حاقنًا تبعيات كلٍّ منها.

أنت تصف، والحاوي يبني. لا تكتب أبدًا new UsersService(new Database(...)). تُعلِن ما يحتاجه كل صنف، ويُجمِّع الحاوي الرسم البياني كاملًا لك.

رموز المزوّدات

يُسجَّل كل مزوّد تحت رمز (token) — مفتاح يستخدمه الحاوي لإيجاده. مع الاختصار القياسي، الرمز هو الصنف نفسه:

providers: [UsersService] // اختصار لـ: providers: [{ provide: UsersService, useClass: UsersService }]

فحين يطلب باني الصنف UsersService، يبحث الحاوي عن الرمز UsersService ويحقن النسخة المطابقة. الصنف يقوم بدورَي النوع ومفتاح البحث معًا.

الحقن برمز غير صنفي

أحيانًا لا يوجد صنف يُستخدم كرمز — ككائن إعدادات أو قيمة بسيطة. تُسجّلها تحت رمز نصّي أو رمزي وتحقنها بـ @Inject():

import { Injectable, Inject } from '@nestjs/common'; // التسجيل providers: [{ provide: 'API_KEY', useValue: 'secret-123' }] // الحقن @Injectable() export class PaymentService { constructor(@Inject('API_KEY') private readonly apiKey: string) {} }
فضّل الثوابت المُصدَّرة على النصوص الخام للرموز (مثل export const API_KEY = 'API_KEY'). فهي تتفادى الأخطاء المطبعية وتتيح لمحرّرك إيجاد كل استخدام.

التبعيات الاختيارية

إن كانت تبعية قد تكون غائبة، علّمها بـ @Optional() ليحقن الحاوي undefined بدل رمي خطأ:

import { Injectable, Optional, Inject } from '@nestjs/common'; @Injectable() export class HttpService { constructor(@Optional() @Inject('HTTP_OPTIONS') private options?: any) {} }

التبعيات الدائرية

إن اعتمد مزوّدان أحدهما على الآخر، فلا يستطيع الحاوي تحديد أيّهما يُبنى أولًا. يحلّ NestJS ذلك بـ forwardRef() التي تؤجّل المرجع حتى يوجد كلاهما:

@Injectable() export class UsersService { constructor( @Inject(forwardRef(() => AuthService)) private readonly authService: AuthService, ) {} }
التبعية الدائرية غالبًا رائحة تصميم سيّئة. قبل اللجوء إلى forwardRef()، اسأل هل يجب أن يكون المنطق المشترك في خدمة ثالثة يعتمد عليها الاثنان. استخدم forwardRef() كملاذ أخير لا كعادة.

الخلاصة

يبني حاوي IoC في NestJS رسم تبعياتك من رموز المزوّدات. مع اختصار الصنف يكون الصنف هو الرمز؛ وللقيم والواجهات تُسجّل تحت رمز نصّي/رمزي وتحقن بـ @Inject(). تسمح @Optional() بتبعيات غائبة، وتعالج forwardRef() المراجع الدائرية التي لا مفرّ منها. تاليًا نستكشف الطرق الأربع لتعريف مزوّد.