iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 7
0
Modern Web

讀官網文件邊走邊學nest.js系列 第 7

Day 7- 驗證DTO屬性-Pipe

前面在AppController下建立User

  @Post()
  create(@Body() userDTO: UserDTO){
    return `使用者:${userDTO.username}已建立`;
  }

從Client傳遞使用者資料至nest並沒有任何驗證,client即便輸入不符合DTO屬性格式,nest也會接受,因為沒有寫驗證的程式碼。

假設欄位限制為

  • username不能超過十個字元
  • email欄位必須符合email格式

nest.js裡有Pipe搭配class-validator、class-transformer套件來實現驗證Client欄位輸入的資訊

流程為

  1. 在UserDTO.ts裡使用class-validator相關Validation Decorators,例如@IsString()為必須為字串

  2. 建立UserDTOValidationPipe實作PipeTransform介面,在transform方法裡撰寫驗證的程式碼

  3. 註冊至Module底下的providers

  4. 到對應的方法宣告@UsePipes並指定UserDTOValidationPipe

  5. 測試

  6. 修改UserDTO.ts如下

import { IsEmail, IsString, Length } from 'class-validator';

export class UserDTO {
    @IsString() 
    @Length(0, 10, { //可以指定錯誤訊息
        message: '長度需要小於十',
    })
    username: string;

    @IsEmail()
    email: string;
}
  1. 建立UserDTOValidationPipe.ts
    在src下,新增shared資料夾並新增UserDTOValidationPipe.ts如下
import { ArgumentMetadata, BadRequestException, Injectable, PipeTransform } from '@nestjs/common';

import { plainToClass } from 'class-transformer';
import { validate } from 'class-validator';

@Injectable()
export class UserDTOValidationPipe implements PipeTransform<any> {
  async transform(value, { metatype }: ArgumentMetadata) {
    if (!metatype || !this.toValidate(metatype)) {
      return value;
    }
    const object = plainToClass(metatype, value);
    const errors = await validate(object);
    if (errors.length > 0) {
      throw new BadRequestException(errors);
    }
    return value;
  }

  private toValidate(metatype): boolean {
    const types = [String, Boolean, Number, Array, Object];
    return !types.find((type) => metatype === type);
  }
}
  1. 註冊至Module底下的providers
    通常Pipe通常放在Shared Module,然後再import到需要的module使用

利用nest cli新增shared.module.ts

nest g module shared

import { Module } from '@nestjs/common';
import { UserDTOValidationPipe } from './pipes/userDTOValidation.pipe';

@Module({
    providers: [
        UserDTOValidationPipe,
    ],
    })
export class SharedModule {}

將ShardModule import 到 AppModule,讓AppModule下的Controller可以使用Shared Module的Pipe

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { SharedModule } from './shared/shared.module';

@Module({
  imports: [SharedModule],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

  1. 到對應的方法宣告@UsePipes並指定UserDTOValidationPipe
    修改app.controller.ts如下
@Post()
  @UsePipes(UserDTOValidationPipe)
  create(@Body() userDTO: UserDTO){
    return `使用者:${userDTO.username}已建立`;
}
  1. 測試
    使用Postman測試結果如下

username輸出超過10個字元,Email格式不正確,nest.js回傳Error Object,在SPA網頁上可以顯示驗證錯誤訊息


上一篇
Day6-Provders & Dependency Injection
下一篇
Day8-Middleware in nest.js
系列文
讀官網文件邊走邊學nest.js31

尚未有邦友留言

立即登入留言