实战使用 NestJS 搭建一个 Admin 后台服务 - 03. DTO参数校验&swagger接口文档生成&swagger 接口文档导入 apifox

实战使用 NestJS 搭建一个 Admin 后台服务 - 01. 项目搭建、配置文件和路由

实战使用 NestJS 搭建一个 Admin 后台服务 - 02. typeorm 操作 mysql&基础 crud

一、DTO参数校验

  • 同样的先安装依赖
bash 复制代码
yarn add class-validator class-transformer

1、使用内置pipe 或者 自定义pipe

  • 一般使用内置管道即可,当然有自定义处理需求的也可以自定义

  • 自定义pipe, 推荐查看官网 docs.nestjs.cn/10/pipes?id...

ts 复制代码
// src/pipe/validation.pipe.ts
import {
  ArgumentMetadata,
  Injectable,
  PipeTransform,
  BadRequestException,
} from '@nestjs/common';
import { validate } from 'class-validator';
import { plainToInstance } from 'class-transformer';
import { Logger } from '../utils/log4js';

@Injectable()
export class MyValidationPipe implements PipeTransform {
  async transform(value: any, { metatype }: ArgumentMetadata) {
    if (!metatype || !this.toValidate(metatype)) {
      // 如果没有传入验证规则,则不验证,直接返回数据
      return value;
    }
    // 将对象转换为 Class 来验证
    const object = plainToInstance(metatype, value);
    const errors = await validate(object);
    if (errors.length > 0) {
      const msg = Object.values(errors[0].constraints)[0]; // 只需要取第一个错误信息并返回即可
      Logger.error(`Validation failed: ${msg}`);
      throw new BadRequestException(`Validation failed: ${msg}`);
    }
    return value;
  }

  private toValidate(metatype: any): boolean {
    const types: any[] = [String, Boolean, Number, Array, Object];
    return !types.includes(metatype);
  }
}

2、修改dto

  • 修改 create-user.dto.ts 不过 CreateUserDto继承了 user.entity.ts 所以直接修改 user.entity.ts 较为方便
ts 复制代码
import { IsNotEmpty } from 'class-validator';
import {
  Entity,
  Column,
  PrimaryGeneratedColumn,
  CreateDateColumn,
  UpdateDateColumn,
} from 'typeorm';

@Entity()
export class User {
  /** 每个实体必须至少有一个主列 */
  @PrimaryGeneratedColumn()
  id: number;

  /** @CreateDateColumn 是一个特殊列,自动为实体插入日期。无需设置此列,该值将自动设置。 */
  @CreateDateColumn({
    type: 'timestamp',
    nullable: false,
    name: 'create_time',
    comment: '创建时间',
  })
  createTime: Date;

  /** @UpdateDateColumn 是一个特殊列,在每次调用实体管理器或存储库的save时,自动更新实体日期。无需设置此列,该值将自动设置。 */
  @UpdateDateColumn({
    type: 'timestamp',
    nullable: false,
    name: 'update_time',
    comment: '更新时间',
  })
  updateTime: Date;

  @IsNotEmpty({
    message: '用户名不能为空',
  })
  @Column({ unique: true, nullable: true, comment: '用户名' })
  username: string;

  @IsNotEmpty({
    message: '邮箱不能为空',
  })
  @Column({ unique: true, nullable: true, comment: '邮箱' })
  email: string;

  @IsNotEmpty({
    message: '手机号不能为空',
  })
  @Column({ unique: true, nullable: true, comment: '手机号' })
  phone: string;

  @Column({ nullable: true, comment: '头像' })
  avatar: string;

  @IsNotEmpty({
    message: '密码不能为空',
  })
  @Column({ nullable: true, comment: '密码' })
  password: string;
}

3、全局使用 or 局部使用

  • 全局使用
  • exceptionFactory 做了一定转化,如下处理后,message 返回的是字符串,且是第一个验证错误
  • new ValidationPipe() 不对exceptionFactory 处理message 返回的是所有校验错误的字符串数组
ts 复制代码
// main.ts
import { BadRequestException, ValidationPipe } from '@nestjs/common';
/** 全局绑定验证管道 或者自定义 new MyValidationPipe() */
app.useGlobalPipes(
  new ValidationPipe({
    exceptionFactory: (errors) => {
      const firstError = errors[0];
      const message =
        firstError.constraints[Object.keys(firstError.constraints)[0]];
      return new BadRequestException(message);
    },
  }),
);
  • 局部使用, 在controller 层使用 users.controller.ts
ts 复制代码
@UsePipes(new ValidationPipe()) // 或者自定义 new MyValidationPipe()
@Post()
create(@Body() createUserDto: CreateUserDto) {
  return this.usersService.create(createUserDto);
}

4、效果展示

  • exceptionFactory 未转化
  • exceptionFactory 转化

二、swagger接口文档生成

bash 复制代码
yarn add @nestjs/swagger swagger-ui-express
  • 修改main.ts
ts 复制代码
const options = new DocumentBuilder()
  .setTitle('Cats example')
  .setDescription('The cats API description')
  .setVersion('1.0')
  .addTag('cats')
  .build();
const document = SwaggerModule.createDocument(app, options);
SwaggerModule.setup('doc', app, document); // 使用doc 不使用api 做一定区分

三、导入api fox

  • apifox 自行下载
  • 可以看到已经导入了,但body内相关参数并没有
  • 接下来进行swagger 装饰器文档编写

四、编写swagger 装饰器文档

1、修改user.entity.ts

ts 复制代码
import { ApiProperty } from '@nestjs/swagger';
import { IsNotEmpty } from 'class-validator';
import {
  Entity,
  Column,
  PrimaryGeneratedColumn,
  CreateDateColumn,
  UpdateDateColumn,
} from 'typeorm';

@Entity()
export class User {
  /** 每个实体必须至少有一个主列 */
  @PrimaryGeneratedColumn()
  id: number;

  /** @CreateDateColumn 是一个特殊列,自动为实体插入日期。无需设置此列,该值将自动设置。 */
  @CreateDateColumn({
    type: 'timestamp',
    nullable: false,
    name: 'create_time',
    comment: '创建时间',
  })
  createTime: Date;

  /** @UpdateDateColumn 是一个特殊列,在每次调用实体管理器或存储库的save时,自动更新实体日期。无需设置此列,该值将自动设置。 */
  @UpdateDateColumn({
    type: 'timestamp',
    nullable: false,
    name: 'update_time',
    comment: '更新时间',
  })
  updateTime: Date;

  @IsNotEmpty({
    message: '用户名不能为空',
  })
  @ApiProperty({ uniqueItems: true, description: '用户名' })
  @Column({ unique: true, nullable: true, comment: '用户名' })
  username: string;

  @IsNotEmpty({
    message: '邮箱不能为空',
  })
  @ApiProperty({ uniqueItems: true, description: '邮箱' })
  @Column({ unique: true, nullable: true, comment: '邮箱' })
  email: string;

  @IsNotEmpty({
    message: '手机号不能为空',
  })
  @ApiProperty({ uniqueItems: true, description: '手机号' })
  @Column({ unique: true, nullable: true, comment: '手机号' })
  phone: string;

  @ApiProperty({ description: '头像' })
  @Column({ nullable: true, comment: '头像' })
  avatar: string;

  @IsNotEmpty({
    message: '密码不能为空',
  })
  @ApiProperty({ description: '密码' })
  @Column({ nullable: true, comment: '密码' })
  password: string;
}

2、重复 三、导入api fox

下一篇

本篇完成了参数校验的相关工作,下篇将进行jwt 的逻辑编写

相关推荐
涡能增压发动积9 小时前
同样的代码循环 10次正常 循环 100次就抛异常?自定义 Comparator 的 bug 让我丢尽颜面
后端
Wenweno0o9 小时前
0基础Go语言Eino框架智能体实战-chatModel
开发语言·后端·golang
于慨9 小时前
Lambda 表达式、方法引用(Method Reference)语法
java·前端·servlet
石小石Orz9 小时前
油猴脚本实现生产环境加载本地qiankun子应用
前端·架构
swg3213219 小时前
Spring Boot 3.X Oauth2 认证服务与资源服务
java·spring boot·后端
从前慢丶9 小时前
前端交互规范(Web 端)
前端
tyung9 小时前
一个 main.go 搞定协作白板:你画一笔,全世界都看见
后端·go
gelald9 小时前
SpringBoot - 自动配置原理
java·spring boot·后端
CHU72903510 小时前
便捷约玩,沉浸推理:线上剧本杀APP功能版块设计详解
前端·小程序
GISer_Jing10 小时前
Page-agent MCP结构
前端·人工智能