高瀬博道の技術ブログ

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

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

前回

takasehiromichiex.com

クラスバリデータを用いたパイプ

Nestは、class-validatorライブラリと連携することができます。

このライブラリを使用すると、デコレータベースのバリデーションを使用できます。

ライブラリをインストールします。

$ npm install --save class-validator class-transformer

インストールしたら、dtoにデコレータを追加します。

src/dto/cat/cat.dto.ts
import { IsInt, IsString } from "class-validator";

export class CreateCatDto {
    @IsString()
    name: string;
    @IsInt()
    age: number;
    @IsString()
    breed: string;
}

パイプを修正しましょう。

src/pipe/validation/validation.pipe.ts
import { ArgumentMetadata, BadRequestException, Injectable, PipeTransform } from '@nestjs/common';
import { plainToInstance } from 'class-transformer';
import { validate } from 'class-validator';



@Injectable()
export class ValidationPipe implements PipeTransform {
  private toValidate(metatype: Function): boolean {
    const types: Function[] = [String, Boolean, Number, Array, Object];
    return !types.includes(metatype);
  }

  async transform(value: any, {metatype}: ArgumentMetadata) {
    if (!metatype || !this.toValidate(metatype)) {
      return value;
    }

    const object = plainToInstance(metatype, value);
    const errors = await validate(object);
    if (errors.length > 0) {
      throw new BadRequestException('Validation failed.');
    }

    return value;
  }
}

まず、transformasyncにしました。

次に、ArgumentMetadataから、metatypeを取り出します。

そして、validateできるtypeかどうかを確認します。

その後、plainToInstanceを使用して、型付きオブジェクトに変更し、validateが実行可能なように修正します。

最後に、validateを実施して、エラーを返すか、値をそのまま返します。

コントローラに適用してみましょう。

src/cats/cats.controller.ts
import { Body, Controller, Get, Post } from '@nestjs/common';
import { CreateCatDto } from 'src/dto/cat/cat.dto';
import { Cat } from './cats.interface';
import { CatsService } from './cats.service';
import { ValidationPipe } from '../pipe/validation/validation.pipe';

@Controller('cats')
export class CatsController {
    constructor(private catsService: CatsService) {}
    
    @Post()
    create(@Body(new ValidationPipe()) createCatDto: CreateCatDto) {
        this.catsService.create(createCatDto);
    }
    @Get()
    findAll(): Cat[] {
        return this.catsService.findAll();
    }
}

@Bodyに引数としてnew ValidationPipe()を渡しました。

まとめ

ここまでで、

  • クラスバリデータを用いたパイプについて

を学びました。

次回は、Guardsについて掘り下げようと思います。

コード

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

github.com

takasehiromichiex.com