NestJSにおけるミドルウェアに関するお勉強記録です。主に以下のページを見て学んだ内容になります。
Middleware | NestJS - A progressive Node.js framework
ミドルウェア
Laravelにもありますね。Controllerに処理が渡る前に何か処理を加えたりするやつです。
ミドルウェアの作成
NestJSでは以下のコマンドでミドルウェアを作成できます。
nest g middleware common/middleware/logger
作成した直後はこんな感じです。
1 2 3 4 5 6 7 8 |
import { Injectable, NestMiddleware } from '@nestjs/common'; @Injectable() export class LoggerMiddleware implements NestMiddleware { use(req: any, res: any, next: () => void) { next(); } } |
これを以下の様に書き換えます。
1 2 3 4 5 6 7 8 9 10 |
import { Injectable, NestMiddleware } from '@nestjs/common'; import { Request, Response, NextFunction } from 'express'; @Injectable() export class LoggerMiddleware implements NestMiddleware { use(req: Request, res: Response, next: NextFunction) { console.log('Request...'); next(); } } |
app.module.tsの編集
app.module.tsを以下の様に書き換えます。
ミドルウェアはデコレータで登録するのではなく、モジュールクラスのconfigure()メソッドで設定します。またNestModuleインターフェースを実装する必要があるとのことです。インターフェースはTypeScriptの構文だからかimplementsしなくても動いてくれたけど。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common'; import { AppController } from './app.controller'; import { AppService } from './app.service'; import { CatsModule } from './cats/cats.module'; import { LoggerMiddleware } from './common/middleware/logger.middleware'; @Module({ imports: [CatsModule], controllers: [AppController], providers: [AppService], }) export class AppModule implements NestModule { configure(consumer: MiddlewareConsumer) { consumer .apply(LoggerMiddleware) .forRoutes('cats'); } } |
ルートの除外
exclude()メソッドで特定のパスからmiddlewareの適用を除外できます。forRoutesではコントローラーを指定することも可能です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
import { MiddlewareConsumer, Module, NestModule, RequestMethod } from '@nestjs/common'; import { AppController } from './app.controller'; import { AppService } from './app.service'; import { CatsModule } from './cats/cats.module'; import { LoggerMiddleware } from './common/middleware/logger.middleware'; import { CatsController } from './cats/cats.controller'; @Module({ imports: [CatsModule], controllers: [AppController], providers: [AppService], }) export class AppModule implements NestModule { configure(consumer: MiddlewareConsumer) { consumer .apply(LoggerMiddleware) .exclude( { path: 'cats', method: RequestMethod.GET }, { path: 'cats', method: RequestMethod.POST }, 'cats/(.*)', ) .forRoutes(CatsController); } } |
関数ミドルウェアの作成
依存関係がないミドルウェアの場合、クラスを作らずに関数だけでも実装できます。logger.middleware.tsを以下のように書き換えます。
1 2 3 4 5 6 |
import { Request, Response, NextFunction } from 'express'; export function logger(req: Request, res: Response, next: NextFunction) { console.log(`Request...`); next(); }; |
app.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 |
import { MiddlewareConsumer, Module, NestModule, RequestMethod } from '@nestjs/common'; import { AppController } from './app.controller'; import { AppService } from './app.service'; import { CatsModule } from './cats/cats.module'; import { logger } from './common/middleware/logger.middleware'; import { CatsController } from './cats/cats.controller'; @Module({ imports: [CatsModule], controllers: [AppController], providers: [AppService], }) export class AppModule implements NestModule { configure(consumer: MiddlewareConsumer) { consumer .apply(logger) .exclude( { path: 'cats', method: RequestMethod.GET }, { path: 'cats', method: RequestMethod.POST }, 'cats/(.*)', ) .forRoutes(CatsController); } } |
これで同様に動作します。
マルチプルミドルウェア
app.module.tsファイルのconfigure()メソッドでMiddlewareConsumerのapplyメソッドに複数のミドルウェアを渡すとその順番で処理が走ります。
consumer.apply(cors(), helmet(), logger).forRoutes(CatsController);
グローバルミドルウェア
main.tsファイルで以下の様に書くと全部のパスで実行されます。クラスの書き方については一応動いたけど、作法としては正しくないかも知れないです。(元のドキュメントには関数ミドルウェアの書き方しか書いてなかったので)
1 2 3 4 5 6 7 8 9 10 11 12 |
import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; import { LoggerMiddleware } from './common/middleware/logger.middleware'; import { logger } from './common/middleware/loggerfunc.middleware'; async function bootstrap() { const app = await NestFactory.create(AppModule); app.use(logger); // 関数ミドルウェアの場合 app.use(new LoggerMiddleware().use); // クラスの場合 await app.listen(3000); } bootstrap(); |
ルートの除外の部分まで実装したサンプルコードを置いておきます。