如何在 NestJS 中使用 DTO 进行验证

这里我们将讨论 NestJS 中的数据传输对象 (DTO) 以及如何使用它们来验证请求。

什么是 DTO?

DTO 本身更多的是为开发人员和使用 API 的人提供指导,以了解请求主体期望的形状,它实际上并没有自己运行任何验证。

但是,使用 TypeScript,我们可以使用内置的验证管道从类验证器库中添加装饰器,并对传入的请求运行验证,以便只有预期的请求可以进入。

开始开发

首先,我们要安装 NestJS CLI,所以打开您选择的终端并输入:

$ npm i -g @nestjs/cli

我们用它的 CLI 初始化一个新的 NestJS 项目。 这可能需要一分钟。 CLI 脚本将询问我们要使用的包管理器。 对于此示例,我选择 NPM。

$ nest new nest-dto-validation

完成此命令后,我们可以在代码编辑器中打开项目。 由于我使用 Visual Studio Code,我将通过键入以下内容打开项目:

$ cd nest-dto-validation
$ code .

如何在 NestJS 中使用 DTO 进行验证

让我们安装一些依赖项。

$ npm i class-validator class-transformer

现在,让我们开始编码。 首先,我们将 ValidationPipe 添加为全局管道。 以下是对其属性的解释:

  • whitelist :删除请求正文中不在 DTO 中的所有属性
  • transform :这个属性将允许我们将属性转换,例如,将整数转换为字符串。 我们今天不讨论这个。

将 src/main.ts

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(3000);
}
bootstrap();

更改为

import { ValidationPipe } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

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

  await app.listen(3000);
}
bootstrap();

修改 main.ts 后,我们需要在 src/ 目录中创建一个名为 app.dts.ts 的新文件。 可以通过以下命令添加它(Mac、Linux):

$ touch src/app.dto.ts

我们要将此内容添加到 src/app.dts.ts 。 该文件将负责验证。 我在文件中添加了一些注释。

import { ArrayMinSize, IsArray, IsBoolean, IsNotEmpty, IsNumber, IsOptional, IsString } from 'class-validator';

export class FormDto {
  // 验证非空字符串
  @IsString()
  @IsNotEmpty()
  public name: string;

  // 仅在它是请求正文的一部分时才进行验证
  @IsString()
  @IsNotEmpty()
  @IsOptional()
  public email: string;

  // 验证整数
  @IsNumber()
  public age: number;

  // 验证整数
  @IsBoolean()
  public acceptedTOS: boolean;

  // 验证非空整数数组
  @IsArray()
  @IsNumber({ allowNaN: false }, { each: true })
  @ArrayMinSize(1)
  public nums: number[];
}

最后但同样重要的是,我们需要修改 src/app.controller.ts 文件。 我们为 POST 请求添加了一个新的路由处理程序。 如大家所见,我们将在上一步中刚刚创建的 FormDTO 类添加为我们的表单类型。

让我们将 src/app.controller.ts 从下面的内容

import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get()
  getHello(): string {
    return this.appService.getHello();
  }
}

更改为

import { Body, Controller, Get, Post } from '@nestjs/common';
import { FormDto } from './app.dto';
import { AppService } from './app.service';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get()
  public getHello(): string {
    return this.appService.getHello();
  }

  @Post()
  public form(@Body() body: FormDto): FormDto {
    return body;
  }
}

就是这样! 现在让我们测试我们的新 POST 路由。 我们可以使用 Postman 等软件,也可以在终端中使用 CURL 命令。

$ curl -X POST http://localhost:3000 -H "Content-Type: application/json" -d '{"age": 1, "name": "Elon Musk", "acceptedTOS": true, "nums": [2]}'

服务端响应如下

{"age":1,"name":"Elon Musk","acceptedTOS":true,"nums":[2]}

太好了,它有效。 现在让我们发送相同的请求,但让我们稍微改变一下正文。 如大家所知,我们需要一个整数作为年龄属性。 所以这次我们要将年龄作为字符串发送:

$ curl -X POST http://localhost:3000 -H "Content-Type: application/json" -d '{"age": "1", "name": "Elon Musk", "acceptedTOS": true, "nums": [2]}'

服务端响应如下

{"statusCode":400,"message":["age must be a number conforming to the specified constraints"],"error":"Bad Request"}

任务完成! 正如预期的那样,我们得到了 400 错误响应。

感谢阅读关于 NestJS 验证的文章。 希望您了解 DTO 现在是如何工作的。