Takip et

NestJS’te Bağımlılık Enjeksiyonu: Kapsamlı Bir Rehber

NestJS’te Bağımlılık Enjeksiyonu: Kapsamlı Bir Rehber Giriş: Bağımlılık Enjeksiyonu Nedir ve Neden Önemlidir? Yazılım geliştirmede “ba

NestJS’te Bağımlılık Enjeksiyonu: Kapsamlı Bir Rehber

Giriş: Bağımlılık Enjeksiyonu Nedir ve Neden Önemlidir?

Yazılım geliştirmede “bağımlılık enjeksiyonu” (Dependency Injection – DI), bir bileşenin ihtiyaç duyduğu diğer bileşenleri (bağımlılıklarını) doğrudan oluşturmak yerine, dışarıdan almasını sağlayan güçlü bir tasarım desenidir. Bu desen, “kontrolün tersine çevrilmesi” (Inversion of Control – IoC) prensibinin özel bir uygulamasıdır. Geleneksel yaklaşımlarda, bir sınıf kendi bağımlılıklarını kendisi oluşturur veya bulur. Bu durum, sınıflar arasında sıkı bir bağ (tight coupling) oluşturur, bu da kodun test edilmesini, bakımını ve genişletilmesini zorlaştırır. Bağımlılık enjeksiyonu sayesinde, bir sınıfın bağımlılıkları dışarıdan “enjekte” edilir, böylece sınıfın kendi bağımlılıklarını yönetme sorumluluğu ortadan kalkar.

Peki, bu neden önemlidir? Bağımlılık enjeksiyonu, yazılım mimarisine bir dizi önemli fayda sağlar:

* Test Edilebilirlik: Bağımlılıklar dışarıdan sağlandığı için, testler sırasında gerçek bağımlılıklar yerine sahte (mock) veya taklit (stub) nesneler enjekte edilebilir. Bu, birim testlerinin daha izole ve güvenilir olmasını sağlar.
* Modülerlik ve Esneklik: Bileşenler arasındaki sıkı bağımlılıkları azaltır. Bir bağımlılığın uygulanması değiştiğinde, onu kullanan sınıfın kodunda değişiklik yapılmasına gerek kalmaz, sadece enjeksiyon mekanizması güncellenir.
* Yeniden Kullanılabilirlik: Daha az bağımlılığı olan veya bağımlılıkları kolayca değiştirilebilen bileşenler, farklı bağlamlarda daha kolay yeniden kullanılabilir.
* Bakım Kolaylığı: Kodun anlaşılması ve bakımı kolaylaşır, çünkü her sınıfın neye ihtiyacı olduğu açıkça belirtilir ve bu ihtiyaçlar dışarıdan karşılanır.
* Ölçeklenebilirlik: Büyük ve karmaşık uygulamalarda bağımlılıkların merkezi olarak yönetilmesi, uygulamanın büyümesiyle birlikte karşılaşılabilecek karmaşıklığı azaltır.

NestJS, modern, ölçeklenebilir ve kurumsal düzeyde uygulamalar oluşturmak için tasarlanmış progresif bir Node.js çatısıdır. TypeScript’i tamamen destekler ve modüler, iyi organize edilmiş kod yazmayı teşvik eder. NestJS’in temelinde yatan en önemli prensiplerden biri de güçlü ve entegre bağımlılık enjeksiyonu sistemidir. NestJS, Angular’dan esinlenerek, uygulamanızın bileşenlerini yönetmek ve bağımlılıkları otomatik olarak çözmek için kendi IoC konteynerini kullanır. Bu makalede, NestJS’teki bağımlılık enjeksiyonu mekanizmasını derinlemesine inceleyeceğiz, temel kavramlardan ileri düzey konulara kadar her yönünü ele alacağız.

NestJS’te Bağımlılık Enjeksiyonunun Temelleri

NestJS’in bağımlılık enjeksiyonu sistemi, uygulamanızın yapı taşlarını, yani “sağlayıcıları” (providers) ve “tüketicileri” (consumers) tanımlamanıza olanak tanır.

Sağlayıcılar (Providers)

Sağlayıcılar, NestJS IoC konteyneri tarafından yönetilen herhangi bir sınıf veya değerdir. Genellikle servisler, depolar, fabrika fonksiyonları veya yapılandırma nesneleri gibi iş mantığını veya veri erişimini kapsülleyen bileşenlerdir. NestJS’te bir sınıfı sağlayıcı olarak işaretlemenin en yaygın yolu @Injectable() dekoratörünü kullanmaktır.

Bir servis sınıfı düşünelim:

// Bu bir kod örneği değil, kavramsal bir gösterimdir.
import { Injectable } from '@nestjs/common';

@Injectable()
class UserService {
  getUsers(): string[] {
    return ['Alice', 'Bob'];
  }
}

@Injectable() dekoratörü, NestJS’e UserService sınıfının enjekte edilebilir bir sağlayıcı olduğunu ve IoC konteyneri tarafından yönetilmesi gerektiğini bildirir. Bu sayede, NestJS bu sınıfın bir örneğini oluşturabilir ve ihtiyaç duyan diğer bileşenlere enjekte edebilir.

Sağlayıcılar, NestJS modüllerinin providers dizisinde kaydedilir. Bir modül, uygulamanın bir alt kümesini organize eden bir yapıdır ve sağlayıcıları, denetleyicileri ve diğer modülleri bir araya getirir.

// Bu bir kod örneği değil, kavramsal bir gösterimdir.
import { Module } from '@nestjs/common';
import { UserService } from './user.service';
import { UserController } from './user.controller';

@Module({
  providers: [UserService],
  controllers: [UserController],
})
class UserModule {}

Bu örnekte, UserService UserModule içinde bir sağlayıcı olarak kaydedilmiştir. Artık UserModule kapsamındaki herhangi bir denetleyici veya başka bir sağlayıcı, UserService‘i bir bağımlılık olarak isteyebilir.

Tüketiciler (Consumers)

Tüketiciler, sağlayıcılardan enjekte edilen bağımlılıkları kullanan sınıflardır. NestJS’te bağımlılık enjeksiyonunun birincil yöntemi “kurucu enjeksiyonu” (constructor injection) olarak adlandırılır. Bir sınıf, ihtiyaç duyduğu bağımlılıkları kurucusunun parametreleri olarak bildirir. NestJS IoC konteyneri, bu parametrelerin türlerini analiz eder ve uygun sağlayıcı örneklerini otomatik olarak sağlar.

Bir denetleyici sınıfı düşünelim:

// Bu bir kod örneği değil, kavramsal bir gösterimdir.
import { Controller, Get } from '@nestjs/common';
import { UserService } from './user.service';

@Controller('users')
class UserController {
  constructor(private readonly userService: UserService) {}

  @Get()
  getAllUsers(): string[] {
    return this.userService.getUsers();
  }
}

Burada, UserController sınıfı UserService‘i kurucusuna enjekte eder. NestJS, UserController‘ın bir örneğini oluştururken, önce UserService‘in bir örneğini bulur veya oluşturur ve ardından bu örneği UserController‘ın kurucusuna geçirir. private readonly anahtar kelimeleri, TypeScript’in kısayol söz dizimidir ve enjekte edilen userService‘i sınıf içinde erişilebilir bir özellik olarak tanımlar.

NestJS’te Sağlayıcı Türleri ve Kapsamları

NestJS, farklı senaryoları karşılamak için çeşitli sağlayıcı türleri ve kapsamları sunar.

Standart Sağlayıcılar (Sınıf Bazlı Sağlayıcılar)

Yukarıda gördüğümüz @Injectable() ile işaretlenmiş ve doğrudan bir modülün providers dizisine eklenen sınıflar, standart sınıf bazlı sağlayıcılardır. NestJS, bu sınıfların tek bir örneğini (singleton) oluşturur ve uygulamanın ömrü boyunca bu örneği yeniden kullanır. Bu, varsayılan ve en yaygın kullanım şeklidir.

Özel Sağlayıcılar (Custom Providers)

Bazen, basit bir sınıf örneği yerine daha karmaşık bir bağımlılık sağlamanız gerekebilir. NestJS, bu tür durumlar için özel sağlayıcılar tanımlamanıza olanak tanır. Özel sağlayıcılar, bir “enjeksiyon tokenı” (injection token) ve bir “sağlayıcı yapılandırma nesnesi” (provider configuration object) kullanılarak tanımlanır.

Enjeksiyon tokenı, NestJS’in hangi bağımlılığı enjekte edeceğini belirlemesini sağlayan bir anahtardır. Genellikle doğrudan sınıf adının kendisi kullanılır, ancak bazen stringler veya semboller de kullanılabilir.

Özel sağlayıcılar için dört ana strateji vardır:

1. useValue: Sabit bir değeri veya önceden oluşturulmuş bir nesneyi enjekte etmek istediğinizde kullanışlıdır. Bu değer, uygulamanın ömrü boyunca aynı kalır.

// Bu bir kod örneği değil, kavramsal bir gösterimdir.
    import { Module } from '@nestjs/common';

    const config = {
      apiKey: 'my-secret-key',
      apiUrl: 'https://api.example.com',
    };

    @Module({
      providers: [
        {
          provide: 'APP_CONFIG', // Enjeksiyon tokenı
          useValue: config,     // Sağlanacak değer
        },
      ],
    })
    class AppModule {}

Bu yapılandırmayı kullanmak için, @Inject() dekoratörü ile özel tokenı belirtmeniz gerekir:

// Bu bir kod örneği değil, kavramsal bir gösterimdir.
    import { Injectable, Inject } from '@nestjs/common';

    @Injectable()
    class MyService {
      constructor(@Inject('APP_CONFIG') private readonly appConfig: any) {
        console.log(appConfig.apiKey);
      }
    }

2. useClass: Bir arayüzü veya soyut bir sınıfı uygulayan farklı bir sınıfı enjekte etmek istediğinizde kullanılır. Bu, uygulamanızın farklı ortamlarda (örneğin, geliştirme ve üretim) farklı uygulamalar kullanmasını sağlamak için harikadır.

// Bu bir kod örneği değil, kavramsal bir gösterimdir.
    import { Module, Injectable } from '@nestjs/common';

    interface ILogger {
      log(message: string): void;
    }

    @Injectable()
    class ConsoleLogger implements ILogger {
      log(message: string) {
        console.log([Console] ${message});
      }
    }

    @Injectable()
    class FileLogger implements ILogger {
      log(message: string) {
        // Dosyaya log yazma mantığı
        console.log([File] ${message});
      }
    }

    @Module({
      providers: [
        {
          provide: ILogger,        // Enjeksiyon tokenı (arayüz/soyut sınıf)
          useClass: ConsoleLogger, // Sağlanacak sınıf
        },
      ],
    })
    class AppModule {}

Burada, ILogger arayüzünü isteyen herkes ConsoleLogger‘ın bir örneğini alacaktır.

3. useFactory: Bağımlılıkların dinamik olarak oluşturulması gerektiğinde veya bağımlılıkların oluşturulması için karmaşık bir mantık gerektiğinde kullanılır. Fabrika fonksiyonları, diğer sağlayıcılara erişebilir ve asenkron işlemler de gerçekleştirebilir.

// Bu bir kod örneği değil, kavramsal bir gösterimdir.
    import { Module, Injectable } from '@nestjs/common';

    @Injectable()
    class DatabaseConfigService {
      getConnectionString(): string {
        return 'mongodb://localhost:27017/mydb';
      }
    }

    @Module({
      providers: [
        DatabaseConfigService,
        {
          provide: 'DATABASE_CONNECTION',
          useFactory: (configService: DatabaseConfigService) => {
            const connectionString = configService.getConnectionString();
            // Veritabanı bağlantısını oluşturma mantığı
            return { connection: 'Connected to ' + connectionString };
          },
          inject: [DatabaseConfigService], // Fabrika fonksiyonunun bağımlılıkları
        },
      ],
    })
    class AppModule {}

inject dizisi, useFactory fonksiyonuna bağımlılık olarak geçirilecek sağlayıcıları belirtir.

4. alias (Takma Adlar): Bir sağlayıcıyı farklı bir enjeksiyon tokenı altında erişilebilir kılmak istediğinizde kullanılır. Bu, özellikle eski kodlarla uyumluluk sağlamak veya kodun yeniden düzenlenmesi sırasında faydalıdır.

// Bu bir kod örneği değil, kavramsal bir gösterimdir.
    import { Module, Injectable } from '@nestjs/common';

    @Injectable()
    class RealService {
      getData(): string { return 'Real data'; }
    }

    @Module({
      providers: [
        RealService,
        {
          provide: 'LEGACY_SERVICE',
          useExisting: RealService, // RealService'in mevcut örneğini kullan
        },
      ],
    })
    class AppModule {}

Artık hem RealService hem de 'LEGACY_SERVICE' tokenı kullanılarak aynı RealService örneği enjekte edilebilir.

Kapsam (Scope)

NestJS sağlayıcıları varsayılan olarak “singleton” kapsamındadır. Bu, uygulamanın ömrü boyunca her sağlayıcının yalnızca bir örneğinin oluşturulduğu ve tüm tüketicilerin aynı örneği paylaştığı anlamına gelir. Ancak, NestJS üç farklı kapsam sunar:

1. DEFAULT (Singleton): Varsayılan kapsamdır. Uygulama başlatıldığında bir kez oluşturulur ve tüm isteklerde yeniden kullanılır.
2. REQUEST: Her gelen HTTP isteği için sağlayıcının yeni bir örneği oluşturulur. İstek sona erdiğinde, örnek çöp toplayıcı tarafından temizlenir. Bu, isteğe özgü verileri (örneğin, kimlik doğrulama bilgileri, işlem bağlamları) yönetmek için kullanışlıdır.

// Bu bir kod örneği değil, kavramsal bir gösterimdir.
    import { Injectable, Scope } from '@nestjs/common';

    @Injectable({ scope: Scope.REQUEST })
    class RequestScopedService {
      private requestId: number;

      constructor() {
        this.requestId = Math.random();
        console.log(RequestScopedService instance created: ${this.requestId});
      }

      getRequestId(): number {
        return this.requestId;
      }
    }

3. TRANSIENT: Bir sağlayıcı her enjekte edildiğinde yeni bir örneği oluşturulur. Bu, her bir bağımlılık noktası için tamamen bağımsız bir örnek istediğinizde kullanışlıdır.

// Bu bir kod örneği değil, kavramsal bir gösterimdir.
    import { Injectable, Scope } from '@nestjs/common';

    @Injectable({ scope: Scope.TRANSIENT })
    class TransientService {
      private id: number;

      constructor() {
        this.id = Math.random();
        console.log(TransientService instance created: ${this.id});
      }

      getId(): number {
        return this.id;
      }
    }

REQUEST veya TRANSIENT kapsamlı sağlayıcılar kullanırken performans etkilerini göz önünde bulundurmak önemlidir, çünkü her örnek oluşturma ek yük getirir.

Gelişmiş Bağımlılık Enjeksiyonu Konuları

NestJS’in DI sistemi, basit enjeksiyonun ötesine geçerek daha karmaşık senaryoları yönetmek için güçlü özellikler sunar.

Dairesel Bağımlılıklar (Circular Dependencies)

İki sınıfın birbirine bağımlı olduğu durumlar “dairesel bağımlılıklar” olarak adlandırılır (örn: ServiceA‘nın ServiceB‘ye ve ServiceB‘nin ServiceA‘ya bağımlı olması). Bu, uygulamanın başlatılmasını engelleyebilecek yaygın bir sorundur. NestJS, bu durumu forwardRef() yardımcı fonksiyonu ile çözmenize olanak tanır.

forwardRef() fonksiyonu, NestJS’e bir referansın henüz tanımlanmamış olabileceğini ve modülün başlatılması sırasında çözülmesi gerektiğini bildirir.

// Bu bir kod örneği değil, kavramsal bir gösterimdir.
import { Injectable, forwardRef, Inject } from '@nestjs/common';

@Injectable()
class ServiceA {
  constructor(@Inject(forwardRef(() => ServiceB)) private readonly serviceB: ServiceB) {}

  doSomething() {
    this.serviceB.doAnotherThing();
  }
}

@Injectable()
class ServiceB {
  constructor(@Inject(forwardRef(() => ServiceA)) private readonly serviceA: ServiceA) {}

  doAnotherThing() {
    this.serviceA.doSomething();
  }
}

Hem ServiceA hem de ServiceB kurucularında forwardRef() kullanarak birbirlerine olan bağımlılıklarını çözebilirler. Ayrıca, modül tanımında da forwardRef() kullanmanız gerekebilir:

// Bu bir kod örneği değil, kavramsal bir gösterimdir.
import { Module, forwardRef } from '@nestjs/common';
import { ServiceA } from './serviceA.service';
import { ServiceB } from './serviceB.service';

@Module({
  imports: [forwardRef(() => AnotherModule)], // Modül seviyesinde dairesel bağımlılık
  providers: [ServiceA, ServiceB],
  exports: [ServiceA, ServiceB],
})
class MyModule {}

Asenkron Sağlayıcılar (Asynchronous Providers)

Veritabanı bağlantıları, dış API istemcileri veya başlatma sırasında asenkron işlemler gerektiren diğer kaynaklar gibi sağlayıcıları oluşturmanız gerekebilir. useFactory stratejisi, asenkron sağlayıcılar oluşturmak için mükemmel bir araçtır. Fabrika fonksiyonunuz bir Promise döndürebilir ve NestJS, bu Promise çözülene kadar uygulamanın başlatılmasını bekleyecektir.

// Bu bir kod örneği değil, kavramsal bir gösterimdir.
import { Module } from '@nestjs/common';

async function createDatabaseConnection() {
  // Asenkron veritabanı bağlantısı kurma işlemi
  return new Promise(resolve => setTimeout(() => resolve({ client: 'DB_CLIENT' }), 2000));
}

@Module({
  providers: [
    {
      provide: 'DATABASE_CONNECTION',
      useFactory: async () => {
        const connection = await createDatabaseConnection();
        console.log('Database connected!');
        return connection;
      },
    },
  ],
})
class AppModule {}

Bu, uygulamanızın veritabanı gibi kritik kaynaklara bağlanmadan önce tamamen başlatılmamasını sağlar.

Dinamik Modüller (Dynamic Modules)

Dinamik modüller, çalışma zamanında yapılandırılabilen modüller oluşturmanıza olanak tanır. Bu, özellikle yapılandırma seçeneklerini kabul eden veya çoklu örnekler gerektiren genel modüller (örneğin, bir yapılandırma modülü, bir veritabanı modülü) oluşturmak için kullanışlıdır. Dinamik modüller genellikle forRoot() veya forFeature() statik metotları aracılığıyla tanımlanır.

Örneğin, bir yapılandırma modülü:

// Bu bir kod örneği değil, kavramsal bir gösterimdir.
import { Module, DynamicModule } from '@nestjs/common';
import { ConfigService } from './config.service';

interface ConfigModuleOptions {
  folder: string;
}

@Module({})
class ConfigModule {
  static forRoot(options: ConfigModuleOptions): DynamicModule {
    return {
      module: ConfigModule,
      providers: [
        {
          provide: 'CONFIG_OPTIONS',
          useValue: options,
        },
        ConfigService,
      ],
      exports: [ConfigService],
    };
  }
}

Uygulama modülünüzde bu dinamik modülü şu şekilde içe aktarabilirsiniz:

// Bu bir kod örneği değil, kavramsal bir gösterimdir.
import { Module } from '@nestjs/common';
import { ConfigModule } from './config.module';

@Module({
  imports: [
    ConfigModule.forRoot({ folder: './config' }),
  ],
})
class AppModule {}

Bu sayede, ConfigModule uygulamanın farklı yerlerinde farklı seçeneklerle yapılandırılabilir.

Modül İhracatı ve İçe Aktarımı (Module Export and Import)

Bağımlılıkların modüller arasında paylaşılması, exports ve imports dizileri aracılığıyla yönetilir. Bir modül, diğer modüllerin kullanabilmesi için sağlayıcılarını exports dizisine ekleyebilir.

// Bu bir kod örneği değil, kavramsal bir gösterimdir.
import { Module } from '@nestjs/common';
import { UserService } from './user.service';

@Module({
  providers: [UserService],
  exports: [UserService], // UserService'i dışa aktar
})
class UserModule {}

Başka bir modülün UserService‘i kullanabilmesi için UserModule‘ü imports dizisine eklemesi gerekir:

// Bu bir kod örneği değil, kavramsal bir gösterimdir.
import { Module } from '@nestjs/common';
import { UserModule } from './user.module';
import { OrderService } from './order.service';

@Module({
  imports: [UserModule], // UserModule'ü içe aktar
  providers: [OrderService],
})
class OrderModule {}

Artık OrderModule içindeki OrderService veya diğer sağlayıcılar, UserService‘i enjekte edebilir.

Özel Enjeksiyon Tokenları (Custom Injection Tokens)

Bazen, bir sınıf türü yerine string veya sembol gibi özel bir token kullanarak bir bağımlılığı enjekte etmek isteyebilirsiniz. Bu, özellikle üçüncü taraf kütüphanelerden değerleri enjekte ederken veya aynı türden birden fazla sağlayıcıyı ayırt etmeniz gerektiğinde kullanışlıdır. @Inject() dekoratörü, özel tokenları belirtmek için kullanılır.

// Bu bir kod örneği değil, kavramsal bir gösterimdir.
import { Injectable, Inject } from '@nestjs/common';

const MY_CONSTANT_TOKEN = 'MY_CONSTANT_TOKEN'; // String token

@Injectable()
class MyService {
  constructor(@Inject(MY_CONSTANT_TOKEN) private readonly myConstant: string) {}

  getConstant(): string {
    return this.myConstant;
  }
}

// Modül tanımında:
import { Module } from '@nestjs/common';
import { MyService } from './my.service';

@Module({
  providers: [
    MyService,
    {
      provide: MY_CONSTANT_TOKEN,
      useValue: 'Hello from custom token!',
    },
  ],
})
class AppModule {}

Semboller de özel token olarak kullanılabilir, bu da string çakışmalarını önleyebilir.

// Bu bir kod örneği değil, kavramsal bir gösterimdir.
import { Injectable, Inject } from '@nestjs/common';

const DATABASE_CONNECTION_TOKEN = Symbol('DATABASE_CONNECTION'); // Sembol token

@Injectable()
class DataRepository {
  constructor(@Inject(DATABASE_CONNECTION_TOKEN) private readonly dbConnection: any) {}

  // ...
}

Pratik Örnekler ve En İyi Uygulamalar

NestJS’in bağımlılık enjeksiyonu sistemi, uygulamalarınızı daha yapılandırılmış, test edilebilir ve sürdürülebilir hale getirmenin anahtarıdır. İşte bazı pratik örnekler ve en iyi uygulamalar:

1. Servisleri Enjekte Etme: En yaygın senaryo, iş mantığını kapsülleyen servis sınıflarını denetleyicilere veya diğer servislere enjekte etmektir.

// Bu bir kod örneği değil, kavramsal bir gösterimdir.
    // user.service.ts
    @Injectable()
    class UserService { / ... / }

    // auth.service.ts
    @Injectable()
    class AuthService {
      constructor(private readonly userService: UserService) {} // UserService enjekte edildi
      // ...
    }

    // auth.controller.ts
    @Controller('auth')
    class AuthController {
      constructor(private readonly authService: AuthService) {} // AuthService enjekte edildi
      // ...
    }

2. Yapılandırma Enjeksiyonu: Uygulama ayarlarını veya çevresel değişkenleri enjekte etmek için özel sağlayıcıları veya dinamik modülleri kullanın. NestJS’in kendi @nestjs/config paketi, bu tür senaryolar için güçlü bir çözümdür.

// Bu bir kod örneği değil, kavramsal bir gösterimdir.
    import { Module } from '@nestjs/common';
    import { ConfigModule, ConfigService } from '@nestjs/config';

    @Module({
      imports: [ConfigModule.forRoot()], // .env dosyasını otomatik yükler
      providers: [
        {
          provide: 'API_KEY',
          useFactory: (configService: ConfigService) => configService.get('API_KEY'),
          inject: [ConfigService],
        },
      ],
      exports: ['API_KEY'],
    })
    class AppConfigModule {}

3. Veritabanı Bağlantıları: Asenkron sağlayıcılar, veritabanı bağlantılarını uygulamanın başlatılması sırasında güvenli ve yönetilebilir bir şekilde kurmak için idealdir.

// Bu bir kod örneği değil, kavramsal bir gösterimdir.
    // database.provider.ts
    import { Provider } from '@nestjs/common';
    import { createConnection } from 'typeorm';

    export const databaseProviders: Provider[] = [
      {
        provide: 'DATABASE_CONNECTION',
        useFactory: async () => await createConnection({
          type: 'postgres',
          host: process.env.DB_HOST,
          port: parseInt(process.env.DB_PORT, 10),
          username: process.env.DB_USERNAME,
          password: process.env.DB_PASSWORD,
          database: process.env.DB_DATABASE,
          entities: [__dirname + '/..//*.entity{.ts,.js}'],
          synchronize: true,
        }),
      },
    ];

    // database.module.ts
    import { Module } from '@nestjs/common';
    import { databaseProviders } from './database.providers';

    @Module({
      providers: [...databaseProviders],
      exports: [...databaseProviders],
    })
    export class DatabaseModule {}

En İyi Uygulamalar:

* Tek Sorumluluk İlkesi (SRP): Her sağlayıcının veya sınıfın tek bir sorumluluğu olmalıdır. DI, bu ilkeye uymayı kolaylaştırır çünkü bağımlılıklar açıkça tanımlanır ve enjekte edilir.
* Küçük ve Odaklanmış Modüller: Uygulamanızı küçük, odaklanmış modüllere ayırın. Her modül kendi bağımlılıklarını yönetmeli ve yalnızca dışa aktarması gereken sağlayıcıları dışa aktarmalıdır.
* Soyutlamalara Bağımlılık: Somut uygulamalara doğrudan bağımlılık yerine arayüzlere veya soyut sınıflara bağımlılık oluşturun. Bu, useClass gibi özel sağlayıcılarla farklı uygulamaları kolayca değiştirebilmenizi sağlar.
* Kapsamları Dikkatli Kullanın: Varsayılan (singleton) kapsam genellikle en iyi performansı sağlar. REQUEST veya TRANSIENT kapsamlarını yalnızca gerçekten ihtiyacınız olduğunda kullanın ve performans üzerindeki potansiyel etkilerini anlayın.
* Dairesel Bağımlılıklardan Kaçının: Mümkün olduğunca dairesel bağımlılıklardan kaçınmak için tasarımınızı gözden geçirin. forwardRef() bir çözümdür, ancak genellikle daha iyi bir mimari tasarımın mümkün olduğuna işaret eder.

Sonuç

NestJS’in bağımlılık enjeksiyonu sistemi, modern Node.js uygulamaları geliştirirken karşılaşılan karmaşıklığı yönetmek için güçlü ve esnek bir araçtır. IoC konteyneri, sağlayıcıların ve tüketicilerin yaşam döngüsünü otomatik olarak yöneterek, geliştiricilerin iş mantığına odaklanmasını sağlar. Standart sınıf tabanlı sağlayıcılardan özel sağlayıcılara, kapsam yönetimine ve dinamik modüllere kadar geniş bir yelpazede özellikler sunarak, NestJS her türlü senaryoya uyum sağlayabilir.

Bağımlılık enjeksiyonunu doğru bir şekilde anlamak ve kullanmak, NestJS uygulamalarınızın test edilebilirliğini, modülerliğini, esnekliğini ve sürdürülebilirliğini önemli ölçüde artıracaktır. Bu rehber, NestJS’teki bağımlılık enjeksiyonunun temelini ve ileri düzey konularını anlamanıza yardımcı olarak, daha iyi ve daha sağlam uygulamalar geliştirmenize katkıda bulunmayı amaçlamıştır. NestJS’in sağladığı bu güçlü mekanizma sayesinde, karmaşık sistemleri bile temiz, düzenli ve yönetilebilir bir şekilde inşa edebilirsiniz.

Yorumlar
İçeriği beğendiniz mi? Bir tartışma başlatın veya görüşlerinizi paylaşın.
Yorum Yaz

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

Gönder

E-posta Bülteni
Yazılım Topluluğuna Katılın
En son güncellemeleri, yaratıcı ipuçlarını ve özel kaynakları doğrudan e-posta kutunuza alın. Tasarım ve inovasyonun geleceğini birlikte keşfedelim.
Exit mobile version