高瀬博道の技術ブログ

高瀬博道の技術ブログです。

もう2023年になったので、今さらNestJSに入門しようと思う - その8

前回

takasehiromichiex.com

ミドルウェアコンシューマ

MiddlewareConsumer は、ヘルパクラスです。ミドルウェアを管理するための組み込みメソッドがいくつか用意されています。

forRoutes()メソッドは、

  • 単一の文字列
  • 複数の文字列
  • RouteInfoオブジェクト
  • コントローラクラス
  • 複数のコントローラクラス

を受け取ることができます。

ほとんどの場合、コンマで区切られたコントローラのリストを渡すだけで済みます。

src/app.module.ts
import { MiddlewareConsumer, Module, NestModule, RequestMethod } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { CatsController } from './cats/cats.controller';
import { CatsModule } from './cats/cats.module';
import { LoggerMiddleware } from './middleware/logger/logger.middleware';

@Module({
  imports: [CatsModule],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer.apply(LoggerMiddleware).forRoutes(CatsController);
  }
}

同様に、apply()メソッドについても、単一または複数のミドルウェアをコンマ区切りで指定することができます。

ミドルウェアから特定のルートを除外する

ミドルウェアの適用から特定のルートを除外したい場合は、exclude()メソッドを使用して、特定のルートを簡単に除外することができます。

exclude()メソッドは、

  • 単一の文字列
  • 複数の文字列
  • 除外するルートを識別するRouteInfoオブジェクト

を引数に取ることができます。

src/app.module.ts
import { MiddlewareConsumer, Module, NestModule, RequestMethod } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { CatsController } from './cats/cats.controller';
import { CatsModule } from './cats/cats.module';
import { LoggerMiddleware } from './middleware/logger/logger.middleware';

@Module({
  imports: [CatsModule],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(LoggerMiddleware)
      .exclude({path: 'cats', method: RequestMethod.GET})
      .forRoutes(CatsController);
  }
}

これで、GETメソッドを読んでも、ミドルウェアは実行されなくなりました。

ファンクショナルミドルウェア

これまで使用してきたミドルウェアは、非常に単純なものでした。

クラスでありながら、メンバも、追加のメソッドも、依存関係もありません。

そのため、クラスではなく、メソッドの形でミドルウェアを実装することができます。

src/middleware/logger/logger.middleware.ts
import { NextFunction, Request, Response } from 'express';

export const logger = (req: Request, res: Response, next: NextFunction) => {
  console.log('Request...');
  next();
}

その後、ルートモジュールに適用します。

src/app.module.ts
import { MiddlewareConsumer, Module, NestModule, RequestMethod } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { CatsController } from './cats/cats.controller';
import { CatsModule } from './cats/cats.module';
import { logger } from './middleware/logger/logger.middleware';

@Module({
  imports: [CatsModule],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(logger)
      .forRoutes(CatsController);
  }
}

これで、ファンクショナルミドルウェアも正常に動作するようになりました。

グローバルミドルウェア

ミドルウェアを全ての登録済みルートに一度にバインドしたい場合は、main.tsでバインドします。

src/main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { logger } from './middleware/logger/logger.middleware';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.use(logger);
  await app.listen(3000);
}
bootstrap();

これで、全てのルートでミドルウェアが実行されるようになりました。

まとめ

ここまでで、

  • forRoutes()メソッドの理解
  • ミドルウェアから特定のルートを除外する方法の理解
  • ファンクショナルミドルウェアの理解
  • グローバルミドルウェアの理解

をすることができました。

次回は、例外フィルタを掘り下げようと思います。

コード

今回のコードは、以下に格納しました。

github.com

takasehiromichiex.com