Nest.js でダイナミックインジェクションを使用して別モジュールからサービスを注入する方法
Nest.js で別モジュールからサービスを注入するには、いくつかの方法があります。ここでは、最も一般的な方法をいくつか紹介します。
プロバイダーを使用する
プロバイダーは、Nest.js においてサービスを登録および管理するための主要なメカニズムです。サービスを注入するには、まずそのサービスをプロバイダーとして登録する必要があります。これは、@Injectable()
デコレータと @Inject()
デコレータを使用して行うことができます。
例:
// services/my-service.ts
import { Injectable } from '@nestjs/common';
@Injectable()
export class MyService {
// ...
}
// app.module.ts
import { Module, Inject } from '@nestjs/common';
import { MyService } from './services/my-service';
@Module({
providers: [MyService],
})
export class AppModule {
constructor(@Inject(MyService) private readonly myService: MyService) {
// ...
}
}
この例では、MyService
サービスを AppModule
に注入しています。@Inject(MyService)
デコレータを使用することで、Nest.js が MyService
のインスタンスを自動的に作成して、AppModule
のコンストラクタに渡します。
モジュール参照を使用すると、別のモジュールのプロバイダーに直接アクセスすることができます。これは、複数のモジュール間でサービスを共有したい場合に便利です。
// services/my-service.ts
import { Injectable } from '@nestjs/common';
@Injectable()
export class MyService {
// ...
}
// app.module.ts
import { Module, Inject } from '@nestjs/common';
import { MyService } from './services/my-service';
import { AnotherModule } from './another.module';
@Module({
imports: [AnotherModule],
})
export class AppModule {
constructor(@Inject(AnotherModule) private readonly anotherModule: AnotherModule) {
const myService = this.anotherModule.get(MyService);
// ...
}
}
この例では、AnotherModule
から MyService
を取得しています。@Inject(AnotherModule)
デコレータを使用することで、Nest.js が AnotherModule
のインスタンスを自動的に作成して渡します。その後、get()
メソッドを使用して、MyService
のインスタンスを取得することができます。
ダイナミックインジェクションを使用すると、実行時に注入するサービスを動的に選択することができます。これは、条件に応じて異なるサービスを注入したい場合に便利です。
// services/my-service.ts
import { Injectable } from '@nestjs/common';
@Injectable()
export class MyService {
// ...
}
export enum ServiceType {
SERVICE_A,
SERVICE_B,
}
// services/service-factory.ts
import { Injectable, Inject } from '@nestjs/common';
import { MyService } from './my-service';
import { ServiceType } from './my-service';
@Injectable()
export class ServiceFactory {
constructor(@Inject(MyService) private readonly myService: MyService) {}
createService(type: ServiceType): MyService {
switch (type) {
case ServiceType.SERVICE_A:
return this.myService;
case ServiceType.SERVICE_B:
// ... Create and return another service
default:
throw new Error('Invalid service type');
}
}
}
// app.module.ts
import { Module, Inject } from '@nestjs/common';
import { MyService, ServiceFactory, ServiceType } from './services';
import { AnotherModule } from './another.module';
@Module({
imports: [AnotherModule],
providers: [ServiceFactory],
})
export class AppModule {
constructor(
@Inject(ServiceFactory) private readonly serviceFactory: ServiceFactory,
) {
const myService = this.serviceFactory.createService(ServiceType.SERVICE_A);
// ...
}
}
この例では、ServiceFactory
クラスを使用して、実行時に注入するサービスを動的に選択しています。createService()
メソッドは、ServiceType
列挙型に基づ
プロバイダーを使用する
// services/my-service.ts
import { Injectable } from '@nestjs/common';
@Injectable()
export class MyService {
constructor() {
console.log('MyService constructor called');
}
doSomething(): string {
return 'Hello from MyService!';
}
}
// app.module.ts
import { Module, Inject } from '@nestjs/common';
import { MyService } from './services/my-service';
@Module({
providers: [MyService],
})
export class AppModule {
constructor(@Inject(MyService) private readonly myService: MyService) {
console.log('AppModule constructor called');
console.log(this.myService.doSomething()); // 'Hello from MyService!'
}
}
この例では、MyService
サービスを AppModule
に注入しています。AppModule
のコンストラクタで、MyService
のインスタンスが自動的に渡されます。
モジュール参照を使用する
// services/my-service.ts
import { Injectable } from '@nestjs/common';
@Injectable()
export class MyService {
constructor() {
console.log('MyService constructor called');
}
doSomething(): string {
return 'Hello from MyService!';
}
}
// another.module.ts
import { Module } from '@nestjs/common';
import { MyService } from './services/my-service';
@Module({
providers: [MyService],
})
export class AnotherModule {
get(service: typeof MyService): MyService {
return this.getProvider(service);
}
}
// app.module.ts
import { Module, Inject } from '@nestjs/common';
import { MyService } from './services/my-service';
import { AnotherModule } from './another.module';
@Module({
imports: [AnotherModule],
})
export class AppModule {
constructor(@Inject(AnotherModule) private readonly anotherModule: AnotherModule) {
console.log('AppModule constructor called');
const myService = this.anotherModule.get(MyService);
console.log(myService.doSomething()); // 'Hello from MyService!'
}
}
この例では、AnotherModule
から MyService
を取得しています。AnotherModule
の get()
メソッドを使用して、MyService
のインスタンスを取得することができます。
ダイナミックインジェクションを使用する
// services/my-service.ts
import { Injectable } from '@nestjs/common';
@Injectable()
export class MyService {
constructor() {
console.log('MyService constructor called');
}
doSomething(): string {
return 'Hello from MyService!';
}
}
export enum ServiceType {
SERVICE_A,
SERVICE_B,
}
// services/service-factory.ts
import { Injectable, Inject } from '@nestjs/common';
import { MyService } from './my-service';
import { ServiceType } from './my-service';
@Injectable()
export class ServiceFactory {
constructor(@Inject(MyService) private readonly myService: MyService) {}
createService(type: ServiceType): MyService {
switch (type) {
case ServiceType.SERVICE_A:
return this.myService;
case ServiceType.SERVICE_B:
// ... Create and return another service
default:
throw new Error('Invalid service type');
}
}
}
// app.module.ts
import { Module, Inject } from '@nestjs/common';
import { MyService, ServiceFactory, ServiceType } from './services';
import { AnotherModule } from './another.module';
@Module({
imports: [AnotherModule],
providers: [ServiceFactory],
})
export class AppModule {
constructor(
@Inject(ServiceFactory) private readonly serviceFactory: ServiceFactory,
) {
console.log('AppModule constructor called');
const myService = this.serviceFactory.createService(ServiceType.SERVICE_A);
console.log(myService.doSomething()); // 'Hello from MyService!'
Nest.js で別モジュールからサービスを注入する方法:その他の方法
上記で紹介した方法に加えて、Nest.js には別モジュールからサービスを注入するための他にもいくつかの方法があります。
グローバルプロバイダーを使用すると、すべてのモジュールのコンストラクタでサービスを利用することができます。これは、アプリケーション全体で広く使用されるサービスを注入する場合に便利です。
// services/my-service.ts
import { Injectable } from '@nestjs/common';
@Injectable()
export class MyService {
// ...
}
// app.module.ts
import { Module } from '@nestjs/common';
import { MyService } from './services/my-service';
@Module({
providers: [MyService],
exports: [MyService],
})
export class AppModule {}
この例では、MyService
をグローバルプロバイダーとして登録しています。exports
配列に MyService
を追加することで、他のモジュールでも利用できるようにします。
ファクトリーメソッドを使用すると、サービスのインスタンスを生成する際に、より多くの制御を行うことができます。これは、サービスのインスタンスを生成する際に、追加のロジックが必要な場合に便利です。
// services/my-service.ts
import { Injectable, FactoryProvider } from '@nestjs/common';
@Injectable()
export class MyService {
constructor() {
console.log('MyService constructor called');
}
doSomething(): string {
return 'Hello from MyService!';
}
}
export const myServiceFactory: FactoryProvider<MyService> = {
provide: MyService,
useFactory: () => {
// ... Create and return a MyService instance
return new MyService();
},
};
// app.module.ts
import { Module, Inject } from '@nestjs/common';
import { myServiceFactory } from './services/my-service';
@Module({
providers: [myServiceFactory],
})
export class AppModule {
constructor(@Inject(MyService) private readonly myService: MyService) {
console.log('AppModule constructor called');
console.log(this.myService.doSomething()); // 'Hello from MyService!'
}
}
この例では、myServiceFactory
というファクトリーメソッドを作成しています。このファクトリーメソッドは、MyService
のインスタンスを生成して返します。AppModule
では、myServiceFactory
をプロバイダーとして登録し、@Inject(MyService)
デコレータを使用してサービスを取得します。
カスタムデコレータを使用すると、サービスの注入をより柔軟に制御することができます。これは、複雑な依存関係を持つアプリケーションを構築する場合に便利です。
// services/my-service.ts
import { Injectable } from '@nestjs/common';
@Injectable()
export class MyService {
// ...
}
// decorators/my-service-decorator.ts
import { Injectable, Inject } from '@nestjs/common';
import { MyService } from './services/my-service';
export const MyServiceDecorator = () => {
return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
const inject = Inject(MyService);
descriptor.value = inject(target, propertyKey, descriptor.value);
};
};
// app.module.ts
import { Module, Inject } from '@nestjs/common';
import { MyService } from './services/my-service';
import { MyServiceDecorator } from './decorators/my-service-decorator';
@Module({
providers: [MyService],
})
export class AppModule {
constructor(@MyServiceDecorator() private readonly myService: MyService) {
console.log('AppModule constructor called');
console.log(this.myService.doSomething()); // 'Hello from MyService!'
}
}
この例では、MyServiceDecorator
というカスタムデコレータを作成しています。このデコレータは、@Inject(MyService)
デコレータと同様に、MyService
のインスタンスを注入します。AppModule
では、MyServiceDecorator
を使用して myService
プロパティを装飾し、サービスを取得します。
javascript node.js typescript