NestJS之12- 数据传输对象DTO

2,823 阅读3分钟

1. 什么是DTO

DTO(Data Transfer Object)是一种用于描述数据模型和数据传输的对象。

它是一种用于在不同层之间传输数据的设计模式。在应用程序的不同组件中,数据通常以各自不同的格式和方式存储。而使用 DTO 可以将这些不同的数据格式和方式转换成一种统一的、标准化的方式,从而方便数据的传输和共享。通过 DTO ,我们可以将数据模型和数据传输途径分开定义,提高应用程序的可扩展性、可维护性和可重用性。

在 NestJS 中,DTO 是一个精简的对象,用于捕获在应用程序的不同部分和层之间传递的数据。并且在业务逻辑和数据访问之间进行解耦。通常,我们会在控制器和服务之间传递 DTO 对象。

对于控制器而言,DTO 是用于接收 HTTP 请求数据的一种数据结构,用于将 HTTP 请求中的数据转换成应用程序需要的数据格式。从服务角度讲,DTO 是用于传递数据模型的一种数据结构,用于将服务返回的数据转换成适合客户端应用程序的格式。

因此,DTO 是 NestJS 中非常重要的概念,它可以帮助我们在应用程序中保持良好的可扩展性和可维护性。

2. 如何使用

2.1 新建一个resource login, 一个pipe login

nest g res login

nest g pi login

  1. 首先先看pipe如何在controller中使用

login.pipe.ts

import { ArgumentMetadata, Injectable, PipeTransform } from '@nestjs/common';

@Injectable()
export class LoginPipe implements PipeTransform {
  transform(value: any, metadata: ArgumentMetadata) {
    console.log(value, metadata);

    return value;
  }
}

login.controller.ts

@Post()
  create(@Param(LoginPipe) createLoginDto: CreateLoginDto) {
    return this.loginService.create(createLoginDto);
  } 

使用curl

curl -d "name=admin&password=123456" -X POST http://localhost:3000/login

image.png

  • value: 对应传入的值
  • type: 对应controller中post的@Body的名称
  • data: 对应接受的属性

使用下面的装饰器 结果不同

@Post()
  create(@Param('name', LoginPipe) createLoginDto: CreateLoginDto) {
    return this.loginService.create(createLoginDto);
  } 
=====
@Body('name', LoginPipe) // 对应value就是admin data是name

image.png

  1. 手动写pipe进行dto验证

需要安装包

npm i -S class-validator
npm i -S class-transformer

create-login.dto.ts

import { IsNotEmpty, IsNumber, IsString, Length } from 'class-validator';
export class CreateLoginDto {
  @IsNotEmpty()
  @IsString()
  @Length(5, 10, {
    message: '字符在5个到10个之间',
  })
  name: string;

  @IsNotEmpty()
  @IsNumber()
  age: number;
}

login.pipe.ts

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

/** 将前端传入的值 加入到管道中 实现验证 */
@Injectable()
export class LoginPipe implements PipeTransform {
  async transform(value: any, metadata: ArgumentMetadata) {
    console.log(value, metadata);
    const DTO = plainToInstance(metadata.metatype, value);
    console.log(DTO);

    const errors = await validate(DTO);
    console.log('打印***errors', errors);

    if (errors.length) {
      throw new HttpException(errors, HttpStatus.BAD_REQUEST);
    }

    return value;
  }
}

login.controller.ts

import { LoginPipe } from './login.pipe';

@Controller('login')
export class LoginController {
  constructor(private readonly loginService: LoginService) {}

  @Post()
  create(@Body(LoginPipe) createLoginDto: CreateLoginDto) {
    return this.loginService.create(createLoginDto);
  }
}

传输字段不符合规则 返回的errors信息 image.png

流程如下: image.png

首先接受前端的数据,@Post的@Body使用LoginPipe,在Login.pipe.ts中就可以获取到值,使用class-transformer中的plainToInstance进行实例化,调用class-validate中的validate方法,可以获取结果是否正确,然后进行相应的返回信息。

  1. 使用NestJS中的全局pipe

上面自己手动配置麻烦,NestJS提供了全局的pipe验证,只需要在

main.ts

import { ValidationPipe } from '@nestjs/common';

app.useGlobalPipes(new ValidationPipe());

验证结果如下:

image.png