LoginSignup
0
0

More than 1 year has passed since last update.

NestJSで動的なパラメーターを渡してインスタンス生成

Posted at

やりたいこと

汎用的なバッチ処理を作りたい。
起動用APIが呼ばれたら内容に応じてバッチ処理を行う。
その際に、内容ごとにロジックを実装して予め登録しておく。
APIから起動パラメタ(処理させる日付)を受け取ってロジックを実行。
(処理内容は今後増える可能性あり)

調査結果

タイトル通りなんですが、NestJSのメカニズムでできるかな?と思ったけど出来なかったのでメモ
似たような質問が以下にありました。

NestJS create a new instance with custom parameters staying in the dependency injection layer

NestJSのuseFactoryで可能かな?と思っていたのですが、サービスクラスなどで動的なパラメーターを渡して
インスタンスを生成、取得することはできないようです。

方法

方法として上記の回答通り、Factoryクラスと生成させたいサービスクラスをDIに登録して、
使いたいサービスのインスタンスをDIしたFactory経由で取得して使うという感じです。
今回は、パラメーターを渡したいのと、パラメーターによって異なるインスタンスが欲しい。
用途としては、異なるロジックをそれぞれのクラスで実装したいという考えからでした。
デザインパターンでいう「Strategy + FactoryMethod」の組合せといった感じでしょうか。

モジュールはファクトリ+生成するサービスで構成します

job.module.ts
const providers = [
  {
    provide: 'JobServiceFactory',
    useClass: JobServiceFactoryImpl,
  },
  {
    provide: XXXJobServiceImpl,
    useClass: XXXJobServiceImpl,
  },
  {
    provide: YYYJobServiceImpl,
    useClass: YYYJobServiceImpl,
  },
];

@Module({
  imports: [],
  providers: providers,
  exports: providers,
})

ファクトリはパラメーターによって異なるサービスを生成して返します

job.service.factory.ts

export interface JobServiceFactory {
  create(jobContext: JobContext): JobService;
}

@Injectable()
export class JobServiceFactoryImpl implements JobServiceFactory {
  constructor(
    private xxxService: XXXJobServiceImpl,
    private yyyService: YYYJobServiceImpl,
  ) {}

  create(jobContext: JobContext): JobService {
    const { name } = jobContext;
    console.log(name);
    if (name === 'xxx') {
      return this.xxxService;
    }
    if (name === 'yyy') {
      return this.yyyService;
    }
  }
}

各ロジック(サービス)はexecute内にロジックを実装

job.[xxx/yyy].service.impl.ts
export interface JobService {
  execute(context: JobContext, param: JobParamType): JobResult;
}

@Injectable()
export class XXXJobServiceImpl implements JobService {
  execute(context: JobContext, param: JobParam): JobResult {
    const result: { [key: string]: string } = {};
    result['name'] = 'XXXJobService';
    result['result'] = 'success';
    result['count'] = '100';

    console.log(
      `execute() context=${JSON.stringify(context)} param=>${JSON.stringify(
        param,
      )} result=>${JSON.stringify(result)}`,
    );

    return { param, result };
  }
}

@Injectable()
export class YYYJobServiceImpl implements JobService {
  execute(context: JobContext, param: JobParam): JobResult {
    const result: { [key: string]: string } = {};
    result['name'] = 'YYYJobService';
    result['result'] = 'success';
    result['count'] = '200';

    console.log(
      `execute() context=${JSON.stringify(context)} param=>${JSON.stringify(
        param,
      )} result=>${JSON.stringify(result)}`,
    );

    return { param, result };
  }
}

実行結果

GET http://localhost:3000/?name=xxx

execute() context={"name":"xxx"} param=>{"params":{"key1":"value1","key2":"value2","key3":"value3"}} result=>{"name":"XXXJobService","result":"success","count":"100"}

GET http://localhost:3000/?name=yyy

execute() context={"name":"yyy"} param=>{"params":{"key1":"value1","key2":"value2","key3":"value3"}} result=>{"name":"YYYJobService","result":"success","count":"200"}

やりたいことができました。
本当はNestJSのメカニズム内で動的なパラメーターを渡してそれに応じて必要なインスタンスを取得、
実行ができればよいのですが、一部はカスタムプロバイダで記述しないとダメでした。
上述の通り、設定ファイルや予め値が取得できる場合は、NestJSのメカニズム内で、上記のことは実現できます。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0