美文网首页
Nest.js - 管道

Nest.js - 管道

作者: stevekeol | 来源:发表于2020-07-13 11:38 被阅读0次
    概念

    管道是具有@Injectable装饰器的
    管道应实现PineTransform接口

    管道可以是参数级,方法级,控制器级,全局级

    管道原理

    管道有两种类型:

    • 转换:管道将输入数据转换成所需的数据输出
    • 验证:对输入数据进行验证,成功则继续传递,失败则抛出异常

    Nest会在Controller的路由处理程序之前插入一个管道,Nest会拦截该方法的调用参数,进行转换/验证处理,然后再调用原方法。

    内置管道

    @nestjs/common自带五个开箱即用的管道:ValidationPipeParseIntPipeParseBoolPipeParseArrayPipeParseUUIDPipe.

    某个场景
    //create-cat.dto
    export class CreateCatDto {
      name: string;
      age: number;
      breed: string;
    }
    
    //cats.controller.ts
    @Post()
    async create(@Body() createCatDto: CreateCatDto) {
      this.catsService.create(createCatDto);
    }
    

    为了确保create()的正确执行,必须验证CreateCatDto的三个属性。此时可考虑验证管道

    • 控制器路由处理程序中验证(不好);
    • 创建验证器类并委托任务(不好);
    • 验证中间件(不好);

    验证管道:第一种验证方式

    创建自定义的验证管道

    Joi库是一个基于结构的验证库。

    //安装依赖
    $ npm install --save @hapi/joi
    $ npm install --save-dev @types/hapi__joi
    
    //自定义一个验证管道
    
    import { PipeTransform, Injectable, ArgumentMetadata, BadRequestException } from '@nestjs/common';
    import { ObjectSchema } from '@hapi/joi';
    
    @Injectable()
    export class JoiValidationPipe implements PipeTransform {
      constructor(private schema: ObjectSchema) {}
    
      transform(value: any, metadata: ArgumentMetadata) {
        const { error } = this.schema.validate(value);
        if (error) {
          throw new BadRequestException('Validation failed');
        }
        return value;
      }
    }
    
    绑定管道(应用管道)
    @Post()
    @UsePipes(new JoiValidationPipe(createCatSchema))
    async create(@Body() createCatDto: CreateCatDto) {
      this.catsService.create(createCatDto);
    }
    
    • 管道可以绑在 controller 或是其方法
    • @UsePipes() 装饰器并创建一个管道实例,并将其传递给 Joi 验证

    验证管道:第二种验证方式

    class-validator允许基于装饰器的验证,可以通过metatype做很多事.

    $ npm i --save class-validator class-transformer
    
    创建相关DTO
    //向CreateCatDto类添加一些装饰器
    
    import { IsString, IsInt } from 'class-validator';
    
    export class CreateCatDto {
      @IsString()
      name: string;
    
      @IsInt()
      age: number;
    
      @IsString()
      breed: string;
    }
    
    创建自定义的验证管道
    //创建ValidationPipe 类
    
    import { PipeTransform, Injectable, ArgumentMetadata, BadRequestException } from '@nestjs/common';
    import { validate } from 'class-validator';
    import { plainToClass } from 'class-transformer';
    
    @Injectable()
    export class ValidationPipe implements PipeTransform<any> {
      //1. transform()是异步的,因为有些class-validator的验证是Promise(异步的)
      //2. metatype采用解构赋值从ArgumentMetadata中提取参数
      async transform(value: any, { metatype }: ArgumentMetadata) {
        //当验证类型不是js的数据类型时,跳过验证
        if (!metatype || !this.toValidate(metatype)) {
          return value;
        }
        //因为请求body中不包含类型信息,若class-validator需要使用相关的DTO,需要做类型转换
        const object = plainToClass(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);
      }
    }
    
    应用管道(参数级别)
    //cats.controller.ts
    @Post()
    async create(@Body(new ValidationPipe()) createCatDto: CreateCatDto) {
      this.catsService.create(createCatDto);
    }
    
    应用管道(方法级别)
    //cats.controller.ts
    @Post()
    @UsePipes(new ValidationPipe()) //ValidationPipe 的实例已就地立即创建
    async create(@Body() createCatDto: CreateCatDto) {
      this.catsService.create(createCatDto);
    }
    
    //cats.controller.ts
    @Post()
    @UsePipes(ValidationPipe) //直接传入类(而非实例),让框架承担实例化责任,并启用依赖注入
    async create(@Body() createCatDto: CreateCatDto) {
      this.catsService.create(createCatDto);
    }
    

    应用管道(全局级别)

    //main.ts
    async function bootstrap() {
      const app = await NestFactory.create(AppModule);
      app.useGlobalPipes(new ValidationPipe()); //用于整个应用程序、每个控制器和每个路由处理程序
      await app.listen(3000);
    }
    bootstrap();
    

    转换管道

    • transform 函数返回的值完全覆盖了参数先前的值
    定义转换管道
    // parse-int.pipe.ts
    import { PipeTransform, Injectable, ArgumentMetadata, BadRequestException } from '@nestjs/common';
    
    @Injectable()
    export class ParseIntPipe implements PipeTransform<string, number> {
      transform(value: string, metadata: ArgumentMetadata): number {
        const val = parseInt(value, 10);
        if (isNaN(val)) {
          throw new BadRequestException('Validation failed');
        }
        return val;
      }
    }
    
    应用管道
    @Get(':id')
    async findOne(@Param('id', new ParseIntPipe()) id) {
      return await this.catsService.findOne(id);
    }
    
    //@Param('id', new ParseIntPipe()) id 的用法?
    
    • ParseIntpipe 将在请求触发相应的处理程序之前执行。

    内置验证管道

    • ValidationPipeParseIntPipe 是内置管道,不必自己构建这些管道
    • ValidationPipe 需要同时安装 class-validatorclass-transformer

    相关文章

      网友评论

          本文标题:Nest.js - 管道

          本文链接:https://www.haomeiwen.com/subject/lanocktx.html