NestJS核心概念之Pipe管道

43 阅读3分钟

在 NestJS 框架中,Pipe 是一个强大的功能,用于在请求处理程序执行之前验证和转换数据。就是在参数传递到处理函数之前做一些验证和转换处理的 class,NestJS 内置了一系列常用的 Pipe,并且允许开发者根据需求创建自定义 Pipe。下面我们将介绍各种内置 Pipe 的使用例子,并展示如何实现一个自定义 Pipe。

创建自定义Pipe

nest g pipe user
import { ArgumentMetadata, Injectable, PipeTransform } from '@nestjs/common';
@Injectable()
export class UserPipe implements PipeTransform {
	transform(value: any, metadata: ArgumentMetadata) {
    //这个里面可以修改传入的值以及验证转入值的合法性
    return value;
	}
}

使用管道

import { Controller,Get,UsePipes,Query} from '@nestjs/common';
import {UserPipe} from '../../user.pipe';
@Controller('user')
export class UserController {    
	@Get()
	index(){
		return '用户页面';
	}
	@Get('pipe')
	@UsePipes(new UserPipe())
	pipe(@Query() info){
		console.log(info);
		return `this is Pipe`;
	}
}

内置的 Pipe

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

ValidationPipe

ValidationPipe 用于自动执行输入数据验证。这通常与类类型 (DTO - Data Transfer Objects) 一起使用。一般依赖与两个库来实现class-validator 和 class-transformer.

npm install class-validator class-transformer -S
// 全局管道
app.useGlobalPipes(new ValidationPipe())

ParseIntPipe

在路由中拿参数一般情况下是 string 类型,ParseIntPipe就对拿到的数据进行转换为数字类型,简单的用法就是直接在控制器方法中添加管道

// localhost:3000/user?water=123
  @Get()
  getHello(@Query('water', ParseIntPipe) water: string): string {
    return water;
  }

ParseFloatPipe

这个管道是转换为浮点数的,可以使用下看看效果

  @Get('water-float')
  getFloat(@Query('water', ParseFloatPipe) water: number) {
    return water + 2;
  }

ParseBoolPipe

通过这个管道把参数值转换为布尔值

  @Get('water-bool')
  getBool(@Query('water', ParseBoolPipe) water: boolean) {
    return water;
  }

ParseArrayPipe

这个管道会把传入的参数按照一定的规则解析成数组类型,但是这个依赖class-validator、class-transformer这两个包

  @Get('water-arr')
  getArr(
    @Query(
      'water',
      new ParseArrayPipe({
        items: Number,
      }),
    )
    water: Array<number>,
  ) {
    return water;
  }

ParseUUIDPipe

可以转换判断下参数是不是 uuid

  @Get('water-uuid')
  getUuid(@Query('water', ParseUUIDPipe) water: string) {
    return water;
  }

ParseEnumPipe

这个管道可以限制传递的参数必须是枚举中的值,如果不是就会报错

  enum E {
    AAA = '111',
  }
  @Get('water-enmu')
  getEnmu(@Query('water', new ParseEnumPipe(E)) water: E) {
    return water;
  }

DefaultValuePipe

这个管道可以用来设置默认值,如果没有没有传递任何参数那么就用默认值

  @Get('water-df')
  getDf(@Query('water', new DefaultValuePipe('water')) water: string) {
    return water;
  }

Nestjs中管道结合Joi库实现数据验证

npm install --save @hapi/joi
npm install --save-dev @types/hapi__joi
import { ArgumentMetadata, Injectable, PipeTransform, BadRequestException } from '@nestjs/common';
import * as Joi from '@hapi/joi';
@Injectable()
export class InfoPipe implements PipeTransform {
  constructor(private readonly schema) { }
  async transform(value: any, metadata: ArgumentMetadata) {
    console.log(value);
    
    const { error } = Joi.validate(value, this.schema)
    if (error) {
      throw new BadRequestException('发送语义有误')
    }
    return value;
  }
}
import * as Joi from '@hapi/joi';

let rootInfo = Joi.object().keys({
  name: Joi.string().required(),
  age: Joi.number().integer().min(6).max(66).required(),
})


@Get()
@UsePipes(new InfoPipe(rootInfo))
root(@Query() info) {
    return `hello world`;
}

class-validator和class-transformer的使用

xxxx.dto.ts文件中添加验证, 完善错误信息提示

import { IsNotEmpty, IsNumber, IsString } from 'class-validator';

export class CreatePostDto {
  @ApiProperty({ description: '文章标题' })
  @IsNotEmpty({ message: '文章标题必填' })
  readonly title: string;

  @IsNotEmpty({ message: '缺少作者信息' })
  @ApiProperty({ description: '作者' })
  readonly author: string;

  @ApiPropertyOptional({ description: '内容' })
  readonly content: string;

  @ApiPropertyOptional({ description: '文章封面' })
  readonly cover_url: string;

  @IsNumber()
  @ApiProperty({ description: '文章类型' })
  readonly type: number;
}

在路由中配置DTO对象

@controller()
class etesxcontroller{
    @post()
     hello(@body(new testpipe()) post:CreatePostDto){}
     
     //testpipe 入参value就是dto可以修改dto的value
     
}

在main.ts中全局注册一下管道ValidationPipe

app.useGlobalPipes(new ValidationPipe());