{T}

NestJS新增功能与DTO数据校验实战

NestJS新增功能与DTO数据校验实战

学习目标:掌握新增功能的完整实现流程、熟练创建 DTO 并使用 class-validator 进行数据校验、理解 ValidationPipe 在新增功能中的作用。


一、新增功能完整流程

1.1 新增功能的完整流程

code
新增功能完整流程:
│
├── 第一步:前端发送请求
│   └── POST /home { "title": "xxx", "url": "xxx", ... }
│
├── 第二步:ValidationPipe 校验数据
│   ├── class-transformer 转换数据
│   ├── class-validator 校验数据
│   └── 校验失败 → 返回错误
│
├── 第三步:Controller 接收请求
│   ├── 使用 @Body() 获取请求体
│   └── 自动校验并转换为 DTO 实例
│
├── 第四步:Service 处理业务逻辑
│   ├── 接收 DTO 实例
│   └── 调用 Prisma 创建数据
│
├── 第五步:Prisma 操作数据库
│   └── prisma.homeResources.create({ data: dto })
│
├── 第六步:数据库返回结果
│   └── 返回新创建的记录
│
└── 第七步:响应给前端
    └── { "id": 1, "title": "xxx", ... }

1.2 新增功能中的数据校验

code
新增功能中的数据校验流程:
│
├── 用户提交数据
│   └── 可能包含:错误类型、恶意字段、缺失字段
│
├── ValidationPipe 自动校验
│   ├── 类型校验:确保数据类型正确
│   ├── 格式校验:确保数据格式正确(如 URL、Email)
│   ├── 必填校验:确保必填字段不为空
│   ├── 枚举校验:确保值在允许范围内
│   └── 恶意字段过滤:自动过滤未定义字段
│
├── 校验成功
│   ├── 数据安全,可以写入数据库
│   └── 避免脏数据污染数据库
│
└── 校验失败
    ├── 立即返回错误信息
    ├── 不进入 Controller
    ├── 不执行业务逻辑
    └── 不访问数据库(性能优化)

二、安装依赖与配置

2.1 安装依赖

bash
# 安装 class-validator 和 class-transformer
$ pnpm add class-validator class-transformer

依赖说明

依赖作用说明
class-validator数据校验提供装饰器校验数据类型和格式
class-transformer数据转换JSON 对象转换为 Class 实例

2.2 配置全局 ValidationPipe

在 main.ts 中配置

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

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

  // 配置全局 ValidationPipe
  app.useGlobalPipes(
    new ValidationPipe({
      transform: true,                   // 自动类型转换
      whitelist: true,                   // 启用白名单
      forbidNonWhitelisted: true,        // 拒绝未定义的字段
      stopAtFirstError: false,           // 返回所有错误
      disableErrorMessages: false,       // 显示详细错误信息
    }),
  );

  // 设置默认版本
  app.enableVersioning({
    type: VersioningType.URI,
    defaultVersion: '1',  // 设置默认版本为 v1
  });

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

配置说明

  • transform: true:自动将请求参数转换为 DTO 类型
  • whitelist: true:自动过滤未在 DTO 中定义的字段
  • forbidNonWhitelisted: true:拒绝包含未定义字段的请求
  • defaultVersion: '1':设置默认版本,无需在 URL 中指定版本

三、创建 DTO(数据传输对象)

3.1 DTO 文件命名规范

code
DTO 文件命名规范:
│
├── 创建 DTO
│   ├── 文件名:create-home-resource.dto.ts
│   ├── 类名:CreateHomeResourceDto
│   └── 作用:定义创建时的数据校验规则
│
├── 更新 DTO
│   ├── 文件名:update-home-resource.dto.ts
│   ├── 类名:UpdateHomeResourceDto
│   └── 作用:定义更新时的数据校验规则
│
├── 查询 DTO
│   ├── 文件名:query-home-resource.dto.ts
│   ├── 类名:QueryHomeResourceDto
│   └── 作用:定义查询参数的校验规则
│
└── 文件位置
    ├── src/modules/home/dto/create-home-resource.dto.ts
    ├── src/modules/home/dto/update-home-resource.dto.ts
    └── src/modules/home/dto/query-home-resource.dto.ts

3.2 对照 Schema 创建 DTO

Schema 定义(prisma/schema.prisma)

prisma
model HomeResources {
  id        Int      @id @default(autoincrement())
  title     String?
  subtitle  String?
  url       String?
  image     String?
  desc      String?
  module    String   @default("home")
  type      String?
  icon      String?
  order     Int      @default(100)
  createdAt DateTime @default(now()) @map("created_at")
  updatedAt DateTime @updatedAt @map("updated_at")

  @@map("home_resources")
}

CreateHomeResourceDto 定义

typescript
// src/modules/home/dto/create-home-resource.dto.ts
import {
  IsString,
  IsOptional,
  IsUrl,
  IsInt,
  IsIn,
  Min,
} from 'class-validator';

export class CreateHomeResourceDto {
  // 可选字符串字段
  @IsOptional()
  @IsString({ message: 'title 必须是字符串' })
  title?: string;

  @IsOptional()
  @IsString({ message: 'subtitle 必须是字符串' })
  subtitle?: string;

  // URL 字段(需要格式校验)
  @IsOptional()
  @IsUrl({}, { message: 'url 格式不正确' })
  url?: string;

  @IsOptional()
  @IsString({ message: 'image 必须是字符串' })
  image?: string;

  @IsOptional()
  @IsString({ message: 'desc 必须是字符串' })
  desc?: string;

  // 枚举字段(必须是指定的值)
  @IsIn(['home', 'study'], { message: 'module 必须是 home 或 study' })
  module: string;

  @IsOptional()
  @IsString({ message: 'type 必须是字符串' })
  type?: string;

  @IsOptional()
  @IsString({ message: 'icon 必须是字符串' })
  icon?: string;

  // 数字字段(有最小值限制)
  @IsOptional()
  @IsInt({ message: 'order 必须是整数' })
  @Min(0, { message: 'order 不能小于 0' })
  order?: number;
}

3.3 DTO 装饰器详解

装饰器分类

code
DTO 装饰器分类:
│
├── 1. 类型校验装饰器
│   ├── @IsString()    # 校验字符串
│   ├── @IsInt()       # 校验整数
│   ├── @IsBoolean()   # 校验布尔值
│   ├── @IsNumber()    # 校验数字
│   └── @IsArray()     # 校验数组
│
├── 2. 可选字段装饰器
│   └── @IsOptional()  # 标记为可选字段
│
├── 3. 格式校验装饰器
│   ├── @IsUrl()       # 校验 URL 格式
│   ├── @IsEmail()     # 校验邮箱格式
│   ├── @IsUUID()      # 校验 UUID 格式
│   └── @IsDateString() # 校验日期字符串
│
├── 4. 枚举校验装饰器
│   └── @IsIn([])      # 校验值是否在列表中
│
├── 5. 数值范围装饰器
│   ├── @Min()         # 最小值
│   └── @Max()         # 最大值
│
└── 6. 长度限制装饰器
    ├── @MinLength()   # 最小长度
    └── @MaxLength()   # 最大长度

装饰器使用示例

typescript
export class CreateHomeResourceDto {
  // 可选字符串
  @IsOptional()
  @IsString({ message: 'title 必须是字符串' })
  title?: string;

  // URL 格式校验
  @IsOptional()
  @IsUrl({}, { message: 'url 格式不正确' })
  url?: string;

  // 枚举值校验
  @IsIn(['home', 'study'], { message: 'module 必须是 home 或 study' })
  module: string;

  // 数字范围校验
  @IsOptional()
  @IsInt({ message: 'order 必须是整数' })
  @Min(0, { message: 'order 不能小于 0' })
  order?: number;
}

3.4 DTO 与 Schema 的对应关系

Schema 字段类型默认值DTO 字段装饰器
titleString?-title?: string@IsOptional() @IsString()
subtitleString?-subtitle?: string@IsOptional() @IsString()
urlString?-url?: string@IsOptional() @IsUrl()
imageString?-image?: string@IsOptional() @IsString()
descString?-desc?: string@IsOptional() @IsString()
moduleString"home"module: string@IsIn(['home', 'study'])
typeString?-type?: string@IsOptional() @IsString()
iconString?-icon?: string@IsOptional() @IsString()
orderInt100order?: number@IsOptional() @IsInt() @Min(0)

重要说明

  • Schema 中的 ? 表示可选字段,DTO 中使用 @IsOptional()
  • Schema 中的 @default() 表示有默认值,DTO 中可以使用 @IsOptional()
  • Schema 中的 String 对应 TypeScript 的 string
  • Schema 中的 Int 对应 TypeScript 的 number

四、Controller 实现新增功能

4.1 使用 @Body 接收请求体

typescript
// src/modules/home/home.controller.ts
import { Controller, Post, Body } from '@nestjs/common';
import { HomeService } from './home.service';
import { CreateHomeResourceDto } from './dto/create-home-resource.dto';

@Controller('home')
export class HomeController {
  constructor(private readonly homeService: HomeService) {}

  @Post()
  async create(@Body() createDto: CreateHomeResourceDto) {
    // createDto 已经经过 ValidationPipe 校验和转换
    // createDto 是 CreateHomeResourceDto 的实例
    return this.homeService.create(createDto);
  }
}

关键点说明

  • @Body() 装饰器:获取请求体数据
  • createDto: CreateHomeResourceDto:指定 DTO 类型
  • ValidationPipe 自动校验并转换数据
  • 校验失败会自动返回错误,不进入 Controller

4.2 ValidationPipe 自动校验流程

code
ValidationPipe 自动校验流程:
│
├── 第一步:接收请求体
│   └── { "title": 123, "url": "invalid", "module": "other" }
│
├── 第二步:class-transformer 转换
│   ├── 将 JSON 对象转换为 CreateHomeResourceDto 实例
│   └── const dto = plainToInstance(CreateHomeResourceDto, body)
│
├── 第三步:class-validator 校验
│   ├── 检查每个属性的装饰器规则
│   ├── title 必须是字符串 →  失败
│   ├── url 必须是 URL 格式 →  失败
│   └── module 必须是 home 或 study →  失败
│
└── 第四步:返回结果
    ├── 校验失败 → 返回错误信息
    └── 校验成功 → 进入 Controller 方法

4.3 Controller 与 Service 的协作

typescript
// Controller 层
@Controller('home')
export class HomeController {
  constructor(private readonly homeService: HomeService) {}

  @Post()
  async create(@Body() createDto: CreateHomeResourceDto) {
    // 1. 接收校验后的数据
    // 2. 调用 Service 处理业务逻辑
    // 3. 返回 Service 的结果
    return this.homeService.create(createDto);
  }
}

// Service 层
@Injectable()
export class HomeService {
  constructor(private prisma: PrismaService) {}

  async create(createDto: CreateHomeResourceDto) {
    // 1. 接收 Controller 传递的数据
    // 2. 调用 Prisma 操作数据库
    // 3. 返回创建的记录
    return this.prisma.homeResources.create({
      data: createDto,
    });
  }
}

五、Service 实现新增功能

5.1 Service 层实现

typescript
// src/modules/home/home.service.ts
import { Injectable } from '@nestjs/common';
import { PrismaService } from '@/prisma/prisma.service';
import { CreateHomeResourceDto } from './dto/create-home-resource.dto';

@Injectable()
export class HomeService {
  constructor(private prisma: PrismaService) {}

  async create(createDto: CreateHomeResourceDto) {
    // 使用 Prisma 创建数据
    return this.prisma.homeResources.create({
      data: createDto,
    });
  }
}

5.2 Prisma create 方法详解

typescript
// Prisma create() 方法签名
prisma.model.create({
  data: {
    // 字段名: 值
  },
  select?: {    // 可选:选择返回的字段
    id: true,
    title: true,
  },
  include?: {   // 可选:包含关联数据
    user: true,
  },
})

// 示例
const resource = await this.prisma.homeResources.create({
  data: {
    title: '新资源',
    url: 'https://example.com',
    module: 'home',
    order: 100,
  },
});

// 返回值:创建的记录对象
{
  id: 1,
  title: '新资源',
  url: 'https://example.com',
  module: 'home',
  order: 100,
  createdAt: '2024-01-01T00:00:00.000Z',
  updatedAt: '2024-01-01T00:00:00.000Z',
}

六、数据校验实战测试

6.1 测试场景一:类型错误

测试数据

json
{
  "title": 123,           //  应该是字符串
  "module": "home"
}

响应结果

json
{
  "statusCode": 400,
  "message": [
    "title 必须是字符串"
  ],
  "error": "Bad Request"
}

说明

  • title 应该是 string 类型,但传入了 number
  • ValidationPipe 自动拦截错误
  • 不会进入 Controller 方法
  • 不会访问数据库

6.2 测试场景二:格式错误

测试数据

json
{
  "url": "invalid-url",   //  不是有效的 URL
  "module": "home"
}

响应结果

json
{
  "statusCode": 400,
  "message": [
    "url 格式不正确"
  ],
  "error": "Bad Request"
}

正确的 URL 格式

json
{
  "url": "https://example.com",  //  正确的 URL 格式
  "module": "home"
}

6.3 测试场景三:枚举值错误

测试数据

json
{
  "module": "other"       //  不在允许的枚举值中
}

响应结果

json
{
  "statusCode": 400,
  "message": [
    "module 必须是 home 或 study"
  ],
  "error": "Bad Request"
}

正确的枚举值

json
{
  "module": "home"        //  正确的枚举值
}

json
{
  "module": "study"       //  正确的枚举值
}

6.4 测试场景四:数字范围错误

测试数据

json
{
  "module": "home",
  "order": -1            //  不能小于 0
}

响应结果

json
{
  "statusCode": 400,
  "message": [
    "order 不能小于 0"
  ],
  "error": "Bad Request"
}

正确的数字范围

json
{
  "module": "home",
  "order": 100           //  正确的数字范围
}

6.5 测试场景五:校验成功

测试数据

json
{
  "title": "新资源",
  "subtitle": "副标题",
  "url": "https://example.com",
  "image": "https://example.com/image.jpg",
  "desc": "资源描述",
  "module": "home",
  "type": "project",
  "icon": "icon-name",
  "order": 100
}

响应结果

json
{
  "id": 1,
  "title": "新资源",
  "subtitle": "副标题",
  "url": "https://example.com",
  "image": "https://example.com/image.jpg",
  "desc": "资源描述",
  "module": "home",
  "type": "project",
  "icon": "icon-name",
  "order": 100,
  "createdAt": "2024-01-01T00:00:00.000Z",
  "updatedAt": "2024-01-01T00:00:00.000Z"
}

说明

  • 所有字段都通过校验
  • 数据成功写入数据库
  • 返回创建的记录

七、使用 DTO 的优势

7.1 传统方式 vs DTO 方式

** 传统方式(不推荐)**:

typescript
@Post()
async create(@Body() body: any) {
  // 手动校验每个字段
  if (!body.title || typeof body.title !== 'string') {
    throw new BadRequestException('title 必须是字符串');
  }

  if (body.url && !this.isValidUrl(body.url)) {
    throw new BadRequestException('url 格式不正确');
  }

  if (!['home', 'study'].includes(body.module)) {
    throw new BadRequestException('module 必须是 home 或 study');
  }

  if (body.order !== undefined) {
    if (typeof body.order !== 'number' || body.order < 0) {
      throw new BadRequestException('order 必须是非负整数');
    }
  }

  // ... 更多校验逻辑

  // 创建数据
  return this.homeService.create(body);
}

** DTO 方式(推荐)**:

typescript
@Post()
async create(@Body() createDto: CreateHomeResourceDto) {
  // 自动校验,无需手动编写校验逻辑
  return this.homeService.create(createDto);
}

对比总结

维度传统方式DTO 方式
代码量大量 if-else装饰器声明
可读性
可维护性难以维护易于维护
复用性无法复用可复用
错误处理手动抛出异常自动返回错误
类型安全any 类型强类型

7.2 DTO 的优势总结

code
DTO 的优势:
│
├── 1. 代码简洁
│   ├── 无需手动编写校验逻辑
│   ├── 使用装饰器声明规则
│   └── 自动校验和转换
│
├── 2. 类型安全
│   ├── TypeScript 强类型
│   ├── IDE 自动提示
│   └── 编译时类型检查
│
├── 3. 易于维护
│   ├── 校验规则集中管理
│   ├── 修改规则只需修改 DTO
│   └── 不影响其他代码
│
├── 4. 可复用
│   ├── DTO 可在多个 Controller 中使用
│   ├── 支持继承和组合
│   └── 减少重复代码
│
└── 5. 文档化
    ├── DTO 定义即文档
    ├── 清晰的数据结构
    └── 易于团队协作

八、完整代码示例

8.1 项目结构

code
src/
├── prisma/
│   ├── prisma.module.ts
│   └── prisma.service.ts
├── modules/
│   └── home/
│       ├── home.module.ts
│       ├── home.controller.ts
│       ├── home.service.ts
│       └── dto/
│           └── create-home-resource.dto.ts
├── app.module.ts
└── main.ts

8.2 完整代码清单

1. main.ts(全局配置)

typescript
// src/main.ts
import { NestFactory } from '@nestjs/core';
import { ValidationPipe, VersioningType } from '@nestjs/common';
import { AppModule } from './app.module';

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

  // 配置全局 ValidationPipe
  app.useGlobalPipes(
    new ValidationPipe({
      transform: true,
      whitelist: true,
      forbidNonWhitelisted: true,
      stopAtFirstError: false,
      disableErrorMessages: false,
    }),
  );

  // 设置默认版本
  app.enableVersioning({
    type: VersioningType.URI,
    defaultVersion: '1',
  });

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

2. create-home-resource.dto.ts(DTO 定义)

typescript
// src/modules/home/dto/create-home-resource.dto.ts
import {
  IsString,
  IsOptional,
  IsUrl,
  IsInt,
  IsIn,
  Min,
} from 'class-validator';

export class CreateHomeResourceDto {
  @IsOptional()
  @IsString({ message: 'title 必须是字符串' })
  title?: string;

  @IsOptional()
  @IsString({ message: 'subtitle 必须是字符串' })
  subtitle?: string;

  @IsOptional()
  @IsUrl({}, { message: 'url 格式不正确' })
  url?: string;

  @IsOptional()
  @IsString({ message: 'image 必须是字符串' })
  image?: string;

  @IsOptional()
  @IsString({ message: 'desc 必须是字符串' })
  desc?: string;

  @IsIn(['home', 'study'], { message: 'module 必须是 home 或 study' })
  module: string;

  @IsOptional()
  @IsString({ message: 'type 必须是字符串' })
  type?: string;

  @IsOptional()
  @IsString({ message: 'icon 必须是字符串' })
  icon?: string;

  @IsOptional()
  @IsInt({ message: 'order 必须是整数' })
  @Min(0, { message: 'order 不能小于 0' })
  order?: number;
}

3. home.controller.ts(Controller 层)

typescript
// src/modules/home/home.controller.ts
import { Controller, Post, Body } from '@nestjs/common';
import { HomeService } from './home.service';
import { CreateHomeResourceDto } from './dto/create-home-resource.dto';

@Controller('home')
export class HomeController {
  constructor(private readonly homeService: HomeService) {}

  @Post()
  async create(@Body() createDto: CreateHomeResourceDto) {
    return this.homeService.create(createDto);
  }
}

4. home.service.ts(Service 层)

typescript
// src/modules/home/home.service.ts
import { Injectable } from '@nestjs/common';
import { PrismaService } from '@/prisma/prisma.service';
import { CreateHomeResourceDto } from './dto/create-home-resource.dto';

@Injectable()
export class HomeService {
  constructor(private prisma: PrismaService) {}

  async create(createDto: CreateHomeResourceDto) {
    return this.prisma.homeResources.create({
      data: createDto,
    });
  }
}

8.3 测试脚本

使用 Postman 测试

bash
# 测试 1:校验成功
POST http://localhost:3000/v1/home
Content-Type: application/json

{
  "title": "新资源",
  "url": "https://example.com",
  "module": "home",
  "order": 100
}

# 响应
{
  "id": 1,
  "title": "新资源",
  "url": "https://example.com",
  "module": "home",
  "order": 100,
  ...
}
bash
# 测试 2:类型错误
POST http://localhost:3000/v1/home
Content-Type: application/json

{
  "title": 123,
  "module": "home"
}

# 响应
{
  "statusCode": 400,
  "message": ["title 必须是字符串"],
  "error": "Bad Request"
}
bash
# 测试 3:格式错误
POST http://localhost:3000/v1/home
Content-Type: application/json

{
  "url": "invalid-url",
  "module": "home"
}

# 响应
{
  "statusCode": 400,
  "message": ["url 格式不正确"],
  "error": "Bad Request"
}

九、常见问题与解决方案

9.1 校验不生效

问题:配置了 DTO,但校验不生效。

原因

  1. 没有安装 class-validator 和 class-transformer
  2. 没有配置全局 ValidationPipe
  3. 没有在 Controller 方法中使用 DTO 类型

解决方案

typescript
// 1. 安装依赖
$ pnpm add class-validator class-transformer

// 2. 配置全局 ValidationPipe
app.useGlobalPipes(new ValidationPipe());

// 3. 在 Controller 中使用 DTO 类型
@Post()
async create(@Body() createDto: CreateHomeResourceDto) {
  return this.homeService.create(createDto);
}

9.2 默认版本未生效

问题:设置了 defaultVersion: '1',但访问 /home 提示 404。

原因:没有正确配置版本控制。

解决方案

typescript
// main.ts
app.enableVersioning({
  type: VersioningType.URI,
  defaultVersion: '1',  // 设置默认版本
});

// 现在可以访问
// GET http://localhost:3000/home(自动使用 v1)
// 等价于
// GET http://localhost:3000/v1/home

9.3 DTO 字段定义错误

问题:DTO 定义时使用了 type 关键字。

原因:混淆了 TypeScript 的 type 和 class。

错误示例

typescript
//  错误:使用 type
export type CreateHomeResourceDto = {
  title?: string;
};

正确示例

typescript
//  正确:使用 class
export class CreateHomeResourceDto {
  @IsOptional()
  @IsString()
  title?: string;
}

说明

  • DTO 必须使用 class,不能使用 typeinterface
  • class 可以添加装饰器,type 不能
  • ValidationPipe 只支持 class

十、学习要点总结

10.1 核心知识点

code
本节核心知识点:
│
├── 新增功能完整流程
│   ├── 前端请求 → ValidationPipe → Controller → Service → Prisma → Database
│   └── 校验失败不进入 Controller,提升性能
│
├── ValidationPipe 配置
│   ├── 全局配置:app.useGlobalPipes(new ValidationPipe())
│   ├── transform: true(自动类型转换)
│   ├── whitelist: true(白名单机制)
│   └── forbidNonWhitelisted: true(拒绝恶意字段)
│
├── DTO 创建
│   ├── 文件命名:create-home-resource.dto.ts
│   ├── 使用 class 定义,不能使用 type
│   ├── 对照 Schema 创建字段
│   └── 使用装饰器定义校验规则
│
├── 常用装饰器
│   ├── @IsOptional():可选字段
│   ├── @IsString():字符串类型
│   ├── @IsInt():整数类型
│   ├── @IsUrl():URL 格式
│   ├── @IsIn([]):枚举值
│   └── @Min():最小值
│
├── Controller 实现
│   ├── @Post():POST 请求
│   ├── @Body():获取请求体
│   └── 参数类型:CreateHomeResourceDto
│
├── Service 实现
│   ├── 接收 DTO 实例
│   └── 调用 Prisma create() 方法
│
└── 测试验证
    ├── 类型错误测试
    ├── 格式错误测试
    ├── 枚举值错误测试
    └── 校验成功测试

10.2 学习路径规划

code
学习路径:
│
├── 第一阶段:理解概念(1 天)
│   ├── 理解新增功能的完整流程
│   ├── 理解 DTO 的作用和优势
│   └── 理解 ValidationPipe 的工作原理
│
├── 第二阶段:实践使用(2-3 天)
│   ├── 创建 DTO 定义
│   ├── 实现 Controller 和 Service
│   ├── 测试校验功能
│   └── 处理各种错误场景
│
└── 第三阶段:深入应用(持续)
    ├── 复杂的校验规则
    ├── 自定义校验装饰器
    ├── 嵌套对象校验
    └── 分组校验

10.3 重要程度标注

code
重要程度说明:
│
├──  必须掌握
│   ├── 新增功能的完整流程
│   ├── ValidationPipe 全局配置
│   ├── 创建 DTO 并使用装饰器
│   ├── Controller 中使用 @Body() 和 DTO
│   └── Service 中使用 Prisma create()
│
├──  重要
│   ├── DTO 文件命名规范
│   ├── 常用装饰器的使用
│   ├── DTO 与 Schema 的对应关系
│   └── 测试校验功能
│
└──  了解
    ├── 自定义错误消息
    ├── DTO 继承和复用
    └── 高级校验规则

重要提示:这一节是 NestJS 新增功能实现的核心内容,理解 DTO 的创建和使用、熟练使用 ValidationPipe 进行数据校验,对实际项目开发非常重要!特别是要掌握如何对照 Schema 创建 DTO,以及如何使用装饰器定义校验规则!

下一节预告:下一节将学习更新功能和删除功能的实现,包括 Update DTO 的创建、PartialType 的使用、Prisma update 和 delete 方法的使用。