LoginSignup
7
2

More than 3 years have passed since last update.

Middleware | NestJS 【翻訳】

Last updated at Posted at 2019-11-06

NestJS公式ドキュメント翻訳

NestJS公式ドキュメント翻訳

原文

Middleware| NestJS - A progressive Node.js web framework

ミドルウェア

ミドルウェアはルートハンドラのに呼び出される関数です。ミドルウェア関数はリクエストオブジェクトとレスポンスオブジェクト、およびアプリケーションのリクエスト/レスポンスサイクルのnext()ミドルウェア関数にアクセスできます。nextミドルウェア関数は、一般にnextという名前の変数によって示されます。

キャプチャ.PNG

Nestのミドルウェアは、デフォルトではexpressのミドルウェアと同等です。Express公式ドキュメントによると、以下のようにミドルウェアの機能について説明しています。

ミドルウェア機能では、次のタスクを実行できます。
  ・コードの実行
  ・リクエストおよびレスポンスオブジェクトに変更を加える
  ・リクエストとレスポンスのサイクルを終了する
  ・スタック内の次のミドルウェア関数を呼び出す
  ・現在のミドルウェア関数でリクエストとレスポンスのサイクルを終了しない場合、次のミドルウェア関数に制御を渡すためにnext()を呼び出す必要があります。そうしなければリクエストがハングします。

カスタムNestミドルウェアは、関数または@Injectable()デコレータを持つクラスのいずれかに実装します。クラスにはNestMiddlewareインターフェースを実装する必要がありますが、関数に特別な要件はありません。クラスメソッドを使用して簡単なミドルウェア機能を実装することから始めましょう。

logger.middleware.ts
import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response } from 'express';

@Injectable()
export class LoggerMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: Function) {
    console.log('Request...');
    next();
  }
}

依存性の注入

Nestミドルウェアは依存性の注入を完全にサポートしています。プロバイダやコントローラと同様に、同じモジュール内で利用可能な依存関係を注入できます。これもconstructorを介して行われます。

ミドルウェアの適用

@Module()デコレータにはミドルウェアを記述する場所がありません。代わりに、モジュールクラスのconfigure()メソッドを使用してセットアップします。ミドルウェアを含むモジュールは、NestModuleインターフェイスを実装する必要があります。 AppModuleレベルでLoggerMiddlewareをセットアップしましょう。

app.module.ts
import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
import { LoggerMiddleware } from './common/middleware/logger.middleware';
import { CatsModule } from './cats/cats.module';

@Module({
  imports: [CatsModule],
})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(LoggerMiddleware)
      .forRoutes('cats');
  }
}

上記の例では、以前にCatsController内で定義された/catsルートハンドラー用のLoggerMiddlewareをセットアップしました。ミドルウェアの設定時に、ルートpathとリクエストmethodを含むオブジェクトをforRoutes()メソッドに渡すことにより、特定のリクエストメソッドに対するミドルウェアをにさらに制限することもできます。以下の例では、RequestMethodをインポートして、目的のリクエストメソッド型を参照していることに注意してください。

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

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

configure()メソッドはasync/awaitを使用して非同期にすることができます(たとえば、configure()内で非同期操作の完了をawaitすることができます)。

ルートワイルドカード

パターンベースのルートもサポートされています。たとえば、アスタリスクはワイルドカードとして使用され、任意の文字の組み合わせに一致します。

forRoutes({ path: 'ab*cd', method: RequestMethod.ALL });

'ab*cd'ルートパスはabcdab_cdabecdなどに一致します。文字+*、および()はルートパスで使用でき、正規表現のサブセットです。ハイフン(-)とドット(.)は文字列ベースのパスによって文字通り解釈されます。

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

MiddlewareConsumerはヘルパークラスです。ミドルウェアを管理するためのいくつかの組み込みメソッドを提供します。それらのすべては、fluent styleで簡単に連鎖することができます。forRoutes()メソッドは単一の文字列、複数の文字列、RouteInfoオブジェクト、コントローラクラス、さらには複数のコントローラクラスを受け取ることができます。ほとんどの場合は、おそらくコンマで区切られたコントローラのリストを渡すだけでしょう。以下は、単一のコントローラを使用した例です。

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

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

apply()メソッドは単一のミドルウェアまたは複数の引数を取り、複数のミドルウェアを指定できます。

多くの場合、特定のルートをミドルウェアの適用にしたい場合があります。(関数ミドルウェアを使用するのではなく、これまで行ってきたように)クラスでミドルウェアを定義する場合、exclude()メソッドを使用して特定のルートを簡単に除外できます。以下に示すように、このメソッドは除外するpathmethodを識別する1つ以上のオブジェクトを取ります。

consumer
  .apply(LoggerMiddleware)
  .exclude(
    { path: 'cats', method: RequestMethod.GET },
    { path: 'cats', method: RequestMethod.POST }
  )
  .forRoutes(CatsController);

上記の例では、LoggerMiddlewareexclude()メソッドに渡される2つを除くCatsController内で定義されたすべてのルートにバインドされます。exclude()メソッドは関数ミドルウェア(クラスではなく関数で定義されたミドルウェア。詳細は以下を参照)では機能しないことに注意してください。さらに、このメソッドはより一般的なルート(ワイルドカードなど)からのパスを除外しません。そのレベルの制御が必要な場合は、パスによって制限するロジックをミドルウェアに直接持たせましょう。たとえば、リクエストURLにアクセスしてミドルウェアロジックを条件付きで適用する必要があります。

関数ミドルウェア

私たちが使用しているLoggerMiddlewareクラスは非常に単純です。メンバー、追加のメソッド、依存関係はありません。クラスではなく単純な関数で定義できないのはなぜでしょうか?実は、関数化することができます。このタイプのミドルウェアは、関数ミドルウェアと呼ばれます。ロガーミドルウェアをクラスベースから関数ミドルウェアに変換して、その違いを説明します。

logger.middleware.ts
export function logger(req, res, next) {
  console.log(`Request...`);
  next();
};

AppModule内で使用します。

app.module.ts
consumer
  .apply(logger)
  .forRoutes(CatsController);

ミドルウェアが依存関係を必要としない場合は、よりシンプルな関数ミドルウェアを代わりに使用することを検討してください。

マルチミドルウェア

前述のように、順次実行される複数のミドルウェアをバインドするにはapply()メソッド内にカンマ区切りのリストを指定するだけです。

consumer.apply(cors(), helmet(), logger).forRoutes(CatsController);

グローバルミドルウェア

ミドルウェアをすべての登録済みルートに一度にバインドする場合、INestApplicationインスタンスによって提供されるuse()メソッドを使用できます。

const app = await NestFactory.create(AppModule);
app.use(logger);
await app.listen(3000);
7
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
2