Dependency Injection は、下記Spring Frameworkでテストしたことがあります。
最近、NodeJSのサーバサイドフレームワークNestJSを使う機会があり、いろいろ調べていると、このDependency Injection(DI)が積極的に使われていました。下記にその部分をクローズアップしている記事がありましたので、実装して試して見ました。
https://blog.devgenius.io/exploring-nest-js-dependency-injection-66a68a10acf7
my.module.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
import { Controller, Get, Inject, Injectable, Module } from '@nestjs/common'; @Injectable() export class MyService1 { doSomething(): string { return 'Something was done'; } } const myValue = { msg: 'Injection!', num: 123, } @Injectable() class ConfigService { private name = 'NestJS' setName(name: string) { this.name = name } getName() { return this.name } } @Injectable() class MyService2 { constructor(private readonly config: ConfigService) {} sayHello() { console.log(`Hello, ${this.config.getName()}!`); } } @Controller('my') export class MyController { //constructor(private readonly myService: MyService) {} @Inject() private readonly myService1: MyService1 //constructor(@Inject('MY_VALUE') private readonly myValue:any){} @Inject('MY_VALUE') private readonly myValue:any @Get() getSomething(): string { console.log(`${this.myValue.msg}:${this.myValue.num}`) return this.myService1.doSomething(); } } @Module({ controllers: [MyController], // providers: [MyService], providers: [ ConfigService, MyService1, { provide: 'MY_SERVICE2', useFactory: (config: ConfigService)=>{ const myService2 = new MyService2(config); myService2.sayHello(); return myService2; }, inject: [ConfigService], }, { provide: 'MY_VALUE', useValue: myValue, } ] }) export class MyModule {} |
普通はファイルを分けて記述するのですが、このような雑多な記述の方が、直感的に理解できるのと、こういう書き方でもいいのかと発見もあるため、あえてやって見ました。
プロジェクト作成後、このファイルだけを追加し、app.module.tsに定義を追加しました。
起動
npm i -g @nestjs/cli
nest new [project name]
cd [project name]
npm run start:dev
1 2 3 4 5 6 7 8 |
import { MyModule } from './my.module' @Module({ imports: [MyModule], controllers: [AppController], providers: [AppService], }) export class AppModule {} |
上記リクエストを実行した上で、Injectable の3つのクラスに注目すると、その注入の記述方法、 挙動が、参考になります。@injectの記述は、コメントのものと同じ意味ですが、constructorと書かれている方が、意味がわかりやすくいですが、下の記述の方がスッキリとしています。
もう少しNestJSの理解を深めるため、DBのORマッパーを使ったサンプルを試して見ました。
「NestJS×TypeORMを7ステップで」
https://zenn.dev/engineerhikaru/articles/69eb781a7fb5e0
上記、動作確認できましたが、ファイルの作成がちょっと面倒と感じたので、自動でリソースを作ってくれるコマンドを試してみました。
nest generate resource demousers
これを元に作成したプロジェクトをgithubにpushしました。
(Blogで内容を説明するにはファイルが多すぎるため)
https://github.com/systemsblue/nestjs-demo01
環境)PostgreSQL ver.16 / Mac(arm64)
インストール
npm i @nestjs/typeorm typeorm pg dotenv
テーブルは自動的に作成されます。(環境は .env ファイル)
VSCodeのThunderClientを使って、動作確認しました。
プログラムはgithubを参考にしていただくとして、ここではDIについて、テスト環境で掘り下げていきます。
https://github.com/systemsblue/nestjs-demo01/blob/main/src/app.controller.spec.ts
このファイルには、通常のテストとモックによって書き換えたテストを記述しています。ここでのポイントは、providersの記述で、”AppService” (名前はこれでなくても良い)をAppServiceとは別物として定義しているところです。これにより、本物とモックの両方を同時にテストしています。あまり意味がないことですが、これがDIの便利さを表しています。
テスト実行
npm test src/app.controller.spec.ts
まだまだ機能が豊富なNestJSですので、調査進めていきたいと思います。
Nestというのは、DIの入れ子、という意味か。。