高瀬博道の技術ブログ

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

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

前回

takasehiromichiex.com

パイプ

パイプは、@Injectable()デコレータがつけられたクラスで、PipeTransformインターフェースを実装します。

パイプは、2通りの使用例があります。

  • transformation
    • 入力データを目的の形式に変換します。文字列から整数へなど
  • validation
    • 入力データを評価し、有効な場合はそのまま渡しますが、有効でない場合は、例外をスローします。

いずれの場合も、パイプはコントローラのルートハンドラによって処理される引数に対して動作します。

Nestは、メソッドが呼び出される直前にパイプを挿入し、パイプはメソッド宛の引数を受け取り、それらを操作します。

この操作の時点でtransformationまたはvalidationが実施され、その後処理済みの引数を利用して、ルートハンドラが呼び出されます。

Nestには、組み込みパイプと、カスタムパイプがあります。

組み込みパイプ

Nestには、以下の組み込みパイプがあります。

  • ValidationPipe
  • ParseIntPipe
  • ParseFloatPipe
  • ParseBoolPipe
  • ParseArrayPipe
  • ParseUUIDPipe
  • ParseEnumPipe
  • DefaultValuePipe
  • ParseFilePipe

パイプをバインドする

パイプをコントローラにバインドしてみましょう。

src/cats/cats.controller.ts
import { Controller, Get, Param, ParseIntPipe } from '@nestjs/common';

@Controller('cats')
export class CatsController {
    @Get(':id')
    findOne(@Param('id', ParseIntPipe) id: number) {
        return id;
    }
}

@Paramに、ParseIntPipeをバインドしました。

postmanで、GET localhost:3000/cats/12345を呼び出すと、以下のように返却されます。

12345

一方で、GET localhost:3000/cats/abcdeを呼び出すと、以下のように返却されます。

{
    "statusCode": 400,
    "message": "Validation failed (numeric string is expected)",
    "error": "Bad Request"
}

カスタムパイプ

独自のカスタムパイプを作成してみましょう。

$ nest g pipe pipe/validation

以下のファイルが作成されました。

src/pipe/validation/validation.pipe.ts
import { ArgumentMetadata, Injectable, PipeTransform } from '@nestjs/common';

@Injectable()
export class ValidationPipe implements PipeTransform {
  transform(value: any, metadata: ArgumentMetadata) {
    return value;
  }
}
src/pipe/validation/validation.pipe.spec.ts
import { ValidationPipe } from './validation.pipe';

describe('ValidationPipe', () => {
  it('should be defined', () => {
    expect(new ValidationPipe()).toBeDefined();
  });
});

全てのパイプは、PipeTransformインターフェースを満たすために、transform()メソッドを実装する必要があります。

valuemetadataの2つの引数があり、valueは現在処理されているメソッドの引数で、metadataは現在処理されているメソッド引数のメタデータです。

メタデータには以下の値があります。

export interface ArgumentMetadata {
  type: 'body' | 'query' | 'param' | 'custom';
  metatype?: Type<unknown>;
  data?: string;
}
  • type
    • 引数が、@Body()@Query()@Param()、またはカスタムパラメータのいずれかを示しています。
  • metatype
    • 引数のメタタイプを提供します。
  • data
    • デコレータに渡される文字列です。

まとめ

ここまでで、

  • パイプについて
  • 組み込みパイプについて
  • パイプをバインドする方法について
  • カスタムパイプについて

を学びました。

次回も、パイプについて掘り下げていこうと思います。

コード

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

github.com

takasehiromichiex.com