美文网首页Nest.js我爱编程
6、Nest.js 中的管道与验证器

6、Nest.js 中的管道与验证器

作者: RoyLin1996 | 来源:发表于2018-08-01 09:51 被阅读380次

    什么是管道(pipe)?

    管道就是一个实现了 PipeTransform 接口并用 @Injectable() 装饰器修饰的类。
    管道的作用简单来说就是,可以将输入的数据处理过后输出。

    我们在前面的例子中将参数验证的逻辑写在了控制器中,这就打破了单一责任原则,控制器只应该处理请求的分发,验证的逻辑应该让验证器来做。
    在 Nest 中正确的做法是,使用管道验证器,改写我们的 findOne 如下:

        @Get(':id')
        async findOne(@Param('id', new ParseIntPipe()) id): Promise<User> {
            return await this.usersService.findOne(id);
        }
    

    我们使用了 @nestjs/common 包中内置的一个管道 ParseIntPipe,它将一个字符串类型的数据转换成一个 int 类型,如果失败则抛出异常,现在访问 http://127.0.0.1:3000/users/exception

    {
        "statusCode":400,
        "date":"2018-7-31",
        "path":"/users/exception"
    }
    

    我们自定义的错误码又没了!这可不是我们想要的结果,看来还是需要自己定义管道验证器。
    现在新建一个管道:

    $ nest g pi users/pipes/user-id
    
    CREATE /src/users/pipes/user-id/user-id.pipe.ts (216 bytes)
    

    去掉 user-id/ 这一层目录,默认生成的管道使用的还是老版本的 @Pipe 装饰器, Nest 5.0 已经修改为 @Injectable 装饰器了,所以我们修改生成的代码再给它加上两行打印语句,如下:

    import { ArgumentMetadata, PipeTransform, Injectable } from '@nestjs/common';
    
    @Injectable()
    export class UserIdPipe implements PipeTransform {
      async transform(value: any, metadata: ArgumentMetadata) {
        console.log(value);
        console.log(metadata);
        return value;
      }
    }
    
    

    PipeTransfrom 接口就只有一个 transfrom 方法, 其中的 value 参数就是我们需要处理的数据源,而 ArgumentMetadata 就是这个对象的一些 元数据(metadate),它的接口定义是下面这样的:

    export interface ArgumentMetadata {
        type: 'body' | 'query' | 'param' | 'custom';
        metatype?: new (...args) => any;
        data?: string;
    }
    

    这里直接引用官方文档的说明:


    image.png

    TypeScript接口在编译期间消失,所以如果你使用接口而不是类,那么元类型的值将是一个 Object。

    现在让我们的管道工作起来,修改 findOne 如下:

        @Get(':id')
        async findOne(@Param('id', new UserIdPipe()) id): Promise<User> {
    
            return await this.usersService.findOne(id);
        }
    

    访问 http://127.0.0.1:3000/users/exception, 看到控制台输出:

    exception
    { metatype: [Function: Object], type: 'param', data: 'id' }
    
    

    我们已经在管道中拿到了参数的值和元数据,我们可以写自己的验证逻辑然后在验证失败的时候让他抛出 ApiException:

    import { ArgumentMetadata, PipeTransform, Injectable, HttpStatus } from '@nestjs/common';
    import { ApiException } from 'common/exceptions/api.exception';
    import { ApiErrorCode } from 'common/enums/api-error-code.enum';
    
    @Injectable()
    export class UserIdPipe implements PipeTransform {
      async transform(value: any, metadata: ArgumentMetadata) {
       
        value = parseInt(value)
    
        if(isNaN(value) || typeof value !== 'number' || value <= 0) {
          throw new ApiException('用户ID无效', ApiErrorCode.USER_ID_INVALID, HttpStatus.BAD_REQUEST);
        }
    
        return value;
      }
    }
    

    访问 http://127.0.0.1:3000/users/exception,发现我们的管道工作的很好,我们自定义的业务状态码也回来了啦:

    {
        "errorCode":10001,
        "errorMessage":"用户ID无效",
        "date":"2018-8-1",
        "path":"/users/exception"
    }
    

    本篇只介绍管道最基本的用法,在后面我们会循序渐进的学习管道的高级用法。

    上一篇:5、Nest.js 中的异常处理和AOP编程
    下一篇:7、Nest.js 中的类验证器

    相关文章

      网友评论

        本文标题:6、Nest.js 中的管道与验证器

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