NestJS に入門してみる

NestJS についての個人的なメモ。

プロジェクトの構築

公式サイトでは @nestjs/cli をグローバルにインストールする手順だが、今回はグローバルを汚さないように以下のコマンドでプロジェクトを作成します。

$ npx @nestjs/cli new プロジェクト名

起動

以下のコマンドでアプリを起動することができます。

pnpm start:dev

初期状態

main.ts がエントリーファイルになっています。

NestFactory.create(AppModule)でNestJSのインスタンスを生成しています。

第一引数に渡している AppModule は、ルートモジュールです。

NestJS では1つ以上のモジュールが必要である。

ポート番号を変更し、フロントと被らないように変更します。

app.listen(process.env.PORT ?? 3001);

http://localhost:3001 へアクセスし、「Hello World!」と返却されていることを確認します。

「Hello World!」を返却するメソッドは、app.service.ts 内の AppService という class の中に書かれていました。

export class AppService {
  getHello(): string {
    return 'Hello World!';
  }
}

現時点で AppService の上に書かれている @Injectable() というデコレータがどのような役割をになっているのか理解できていません。

次に app.service.ts がどこで呼ばれているのかを確認します。

app.controller.ts と app.module.ts の2ファイルから呼ばれていることわかりました。

app.module.ts は app.service.ts だけではなく、app.controller.ts を呼び出していました。

先に app.controllers.ts を確認します。

ここで初めて気づきますが、NestJS はデコレーターを使用する場面が多いです!!!

@Controller() というデコレータを定義することで app.controllers.ts で定義した class をコントローラーとして定義することができるようです。

また、引数にパスを設定することができます。

下記のように変更し、http://localhost:3001/users にアクセスすると先ほどと同じように「Hello World!」が返却されることを確認することができます。

@Controller('users')

AppController という class の中では以下のようなメソッドが作成されていました。

@Get()
getHello(): string {
  return this.appService.getHello();
}

基本的にコントローラーはルーティングの役割とサービスで定義したメソッドを呼び出す役割があるようです。

コントローラーでは詳細な機能の実装はせず、詳しい部分はサービスにお願いするイメージだと思います。

最後に app.module.ts を確認します。

@Module() というデコレータの引数にコントローラーとサービス、そして imports が設定されています。

@Module({
  imports: [],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

NestJS ではこれまで確認してきた コントローラーとサービスで構築する機能の1つのモジュールという単位で呼ぶようです。

app.module.ts ではこのモジュールを定義するようです。

試しに Users というモジュールを作成しようと思います。

事前に先ほど追加した main.service.ts で定義した @Controller('users') を @Controller() に戻します。

users/index.service.ts を作成し、以下の内容を記述します。

import { Injectable } from '@nestjs/common';
import type { User } from './../types/index.d.ts';

@Injectable()
export class UsersService {
  getUsers(): User[] {
    return [
      {
        id: 1,
        name: 'John',
      },
    ];
  }
}

型情報はコントローラーでも使用するため、外部ファイルとして定義します。

type User = {
  id: number;
  name: string;
};

次にコントローラーを作成します。

import { Controller, Get } from '@nestjs/common';
import { UsersService } from './index.service';
import type { User } from './../types/index.d.ts';

@Controller('users')
export class UsersController {
  constructor(private readonly usersService: UsersService) {}

  @Get()
  getUsers(): User[] {
    return this.usersService.getUsers();
  }
}

モジュールを作成します。

import { Module } from '@nestjs/common';
import { UsersController } from './index.controller';
import { UsersService } from './index.service';

@Module({
  controllers: [UsersController],
  providers: [UsersService],
})
export class UsersModule {}

最後に app.module.ts に作成したコントローラーとサービスを追記します。

別のモジュールを読み込む場合は imports に書くようです。

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UsersModule } from './users/index.module';

@Module({
  imports: [UsersModule],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

http://localhost:3001/usres にアクセスし、{"id":1,"name":"John"} というユーザーのデータが返却されていることを確認します。

環境変数の設定

NestJSで環境変数を扱うには@nestjs/configを使用します。

まずはインストールします。

pnpm add @nestjs/config

次にapp.module.tsのimportsに以下を追記します。

imports: [
  ConfigModule.forRoot({
    isGlobal: true, // グローバルに登録します
  }),
],

次に.envファイルを用意し、環境変数を宣言します。

DATABASE_USER=test

最後に環境変数をserviceで呼び出してみます。

export class AppService {
  constructor(private configService: ConfigService) {}

  getHello(): string {
    return this.configService.get<string>('DATABASE_USER');
  }
}

testという文字列が返ってくることを確認します。