iT邦幫忙

2024 iThome 鐵人賽

DAY 8
1

nestjs 分層元件 Pipe 與 Serialization

目標

  1. 介紹 nestjs 分層元件 Pipe
  2. 介紹 Serialization 作用

概念

在 nestjs 中,主要透過 Pipe 這個元件來做輸入資料格式的驗證與資料格式的轉換。

Pipe 主要針對 Controller 內部的 handler 的參數做處理。

透過 Pipe 元件, handler 的參數會被逐個依照指定的格式做檢查並且做轉換,格式化成系統內部需要的格式。轉換格式的概念叫作 Serialization ,是指依照特定格式去轉換資料。

nestjs Pipe 元件

nestjs Pipe 元件,主要是一個類別去實作 PipeTransform 介面。具體透過 transform 方法實做出轉換資料的細節。

nestjs 內建的 Pipe

  • ValidationPipe
  • ParseIntPipe
  • ParseBoolPipe
  • ParseArrayPipe
  • ParseUUIDPipe
  • DefaultValuePipe

第一個 ValidationPipe 是可以在 Dto 上面做驗證設定,透過 ValidationPipe 可以檢核出哪些欄位資料格式不符預期。 Parse系列的 Pipe 則是可以把輸入轉換成預期的格式。 DefaultValuePipe 則是可以把參數自動帶入預設值。

客製化 ValidationPipe 範例

為了使用 ValidationPipe ,會需要加入 class-validatorclass-transformer 套件做開發,安裝指令如下:

pnpm i -S class-validator class-transformer

create-cat.dto.ts 如下

import { IsString, IsInt } from 'class-validator';

export class CreateCatDto {
  @IsString()
  name: string;

  @IsInt()
  age: number;

  @IsString()
  breed: string;
}

可透過 validate.pipe.ts 如下實作來進行轉換與驗證

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

@Injectable()
export class ValidationPipe implements PipeTransform<unknown> {
  async transform(value: unknown, { 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;
  }

  private toValidate(metatype: Function): boolean {
    const types: Function[] = [String, Boolean, Number, Array, Object];
    return !types.includes(metatype);
  }
}

套用的範圍有以下三種:

  1. handler scope:
@Post()
@UsePipes(ValidationPipe)
createPet(@Body() createPetDto: CreatePetDto) {
  return this.petsService.createPet(createPetDto);
}
  1. controller scope:
@Controller('pets')
@UsePipes(ValidationPipe)
export class PetsController {
  
  constructor(private readonly petsService: PetsService) {}
  
  ...
}
  1. global app scope:
async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalPipes(new ValidationPipe());
  await app.listen(3000);
}
bootstrap()

使用 build in 的 Pipe

如果是轉換內部值的 Pipe 需要特別寫入要轉換的物件之後如下:

@Get()
async findOne(@Query('id', ParseIntPipe) id: number) {
  return this.catsService.findOne(id);
}

設定只驗證有注記的欄位 whitelist

app.useGlobalPipes(
  new ValidationPipe({
    whitelist: true,
  }),
);

設定自動轉換型別 transform

app.useGlobalPipes(
  new ValidationPipe({
    transform: true,
  })
);

結論

nestjs 透過 Pipe 元件來把輸入的資料做驗證與轉換,分擔了資料格式化的邏輯。實務上,常常使用 ValidattionPipe 來對輸入做驗證,確保輸入如逾期。


上一篇
nestjs 分層元件 Guard
下一篇
nestjs 分層元件 Filter
系列文
透過 nestjs 框架,讓 nodejs 系統維護度增加31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言