Dev Study
← コース一覧

NestJS

Node.js でサーバーサイドアプリケーションを構築するためのフレームワーク NestJS を学ぶコースです。1レッスン1テーマの小さなステップで、公式ドキュメントの流れに沿って保守しやすい API の作り方を身につけます。

公式ドキュメント: NestJS Documentation

基礎

  1. 1
    NestJSとは
    NestJS は Node.js 上で動くサーバーサイドフレームワークで、アプリを「コントローラ」「プロバイダ」「モジュール」という3種類の部品に分けて組み立てます。TypeScript を前提に設計されており、部品の種類と置き場所をフレームワーク側が決めてくれるのが特徴です。
  2. 2
    main.ts とブートストラップ
    NestJS アプリのエントリーポイントは main.ts です。NestFactory.create() にルートモジュール(AppModule)を渡してアプリのインスタンスを作り、app.listen() でポートを指定して HTTP サーバーを起動します。この一連の起動処理をブートストラップと呼びます。
  3. 3
    コントローラと @Get
    コントローラは HTTP リクエストを最初に受け取る部品です。クラスに @Controller("users") を付けると /users 配下のパスを担当し、メソッドに @Get() を付けるとそのメソッドが GET リクエストの処理(ハンドラ)になります。POST なら @Post() のように、HTTP メソッドごとにデコレータが用意されています。
  4. 4
    ルートパラメータと @Param
    GET /users/123 のように URL の一部が可変になる場合は、@Get(":id") とコロン付きでパスを宣言します。ハンドラの引数に @Param("id") を付けると、その位置の値を受け取れます。
  5. 5
    リクエストボディと @Body
    POST や PUT で送られてくる JSON ボディは、ハンドラの引数に @Body() を付けて受け取ります。NestJS が JSON のパースを済ませてくれるので、引数にはオブジェクトがそのまま入ってきます。

DIとモジュール

  1. 6
    DIの考え方
    DI(依存性の注入)とは、クラスが必要とする別のクラスを自分で new するのではなく、外部から渡してもらう設計です。NestJS の中心にはこの仕組みを自動化する「DIコンテナ」があり、クラスの生成と受け渡しをフレームワークが肩代わりします。
    実行可
  2. 7
    プロバイダとサービス
    プロバイダは DIコンテナに登録してアプリ内で注入できるようにしたクラスの総称で、その代表がビジネスロジックを担う「サービス」です。クラスに @Injectable() を付けると注入可能になり、利用側はコンストラクタの引数に型を書くだけで受け取れます。
  3. 8
    モジュール — 機能のまとまり
    モジュールは、関連するコントローラとプロバイダを1つの機能単位に束ねる部品です。@Module() デコレータに controllers と providers を列挙して登録します。アプリ全体は必ず1つのルートモジュール(AppModule)から始まり、機能モジュールを imports でぶら下げていきます。
  4. 9
    モジュール間の共有 — exports と imports
    モジュール内の providers は、そのままでは同じモジュールの中からしか注入できません。他のモジュールにサービスを使わせたいときは、提供側が exports にそのプロバイダを載せ、利用側が imports でモジュールごと取り込みます。

リクエスト処理パイプライン

  1. 10
    DTO — リクエストの形を定義する
    DTO(Data Transfer Object)は、リクエストボディの形を表す専用クラスです。CreateUserDto のように「操作名 + Dto」という名前でクラスを作り、@Body() の型注釈に使います。インラインの型注釈と違い、ボディの形に名前が付いて再利用できるようになります。
  2. 11
    ValidationPipe — 入力の自動検証
    ValidationPipe は、DTO に書いた検証ルールを自動で実行する仕組みです。class-validator の @IsString() や @Min() などのデコレータを DTO のプロパティに付け、main.ts で app.useGlobalPipes(new ValidationPipe()) を設定すると、@Body() で受け取る値が届く前に検証されます。
  3. 12
    カスタムパイプ — transform の契約
    パイプの正体は、PipeTransform インターフェースの transform() メソッドを実装したクラスです。「ハンドラに渡る直前の値を受け取り、変換した値を返す。不正なら例外を投げる」というのがパイプの契約のすべてで、ValidationPipe もこの契約に従う1つの実装にすぎません。
    実行可
  4. 13
    ガード — 認証・認可の入口
    ガードは「このリクエストを処理してよいか」をハンドラ実行前に判定する部品です。CanActivate インターフェースを実装したクラスを作り、canActivate() で true を返せば通過、false を返せば 403 Forbidden で拒否されます。適用は @UseGuards() デコレータで行います。
  5. 14
    インターセプター — 処理の前後に割り込む
    インターセプターは、ハンドラの実行を前後から挟み込む部品です。NestInterceptor インターフェースの intercept() を実装し、next.handle() を呼ぶとハンドラ本体が実行されます。その呼び出しの前後にコードを置けるため、「実行前の準備」と「実行後の加工」を1か所に書けます。
  6. 15
    ミドルウェア — ルーティング前の共通処理
    ミドルウェアは、どのハンドラが処理するか決まるより前にリクエストへ触れる部品です。NestMiddleware の use(req, res, next) を実装し、最後に next() を呼んで処理を先へ渡します。適用はモジュールの configure() で、どのパスに効かせるかを指定します。
  7. 16
    例外フィルタ — エラーレスポンスの統一
    例外フィルタは、処理中に投げられた例外を捕まえてエラーレスポンスの形を決める部品です。@Catch(HttpException) を付けたクラスで ExceptionFilter を実装し、catch() の中でステータスコードとレスポンスボディを組み立てます。

実務テクニック

  1. 17
    環境変数と ConfigModule
    DB の接続先や API キーのような環境ごとに変わる値は、コードに直書きせず環境変数で渡します。NestJS では @nestjs/config パッケージの ConfigModule.forRoot() を AppModule に登録すると .env ファイルが読み込まれ、ConfigService を注入して config.get("KEY") で値を取り出せます。
  2. 18
    リクエストのライフサイクル全体像
    ここまで学んだ部品は、1つのリクエストに対して決まった順序で実行されます。大きな流れは「ミドルウェア → ガード → インターセプター(前) → パイプ → ハンドラ → インターセプター(後)」で、途中で投げられた例外は例外フィルタが受け止めます。
    実行可