NestJS中如何管理接口、模型与验证类?解决冗余代码痛点
NestJS 减少DTO、Mongoose Schema与接口重复代码的实践
问题背景
我在新项目中使用NestJS,被大量样板代码困扰,尤其是DTO类、Mongoose Schema和接口的编写。之前的流程是:先定义描述集合文档字段的接口,再编写实现该接口的DTO验证类,还要编写与接口镜像的Mongoose Schema(最初以为Schema无法直接实现接口,后来修正了这一认知)。这种方式导致修改文档结构时需要在三处同步更新,并且Schema与DTO存在重复的验证逻辑。
我有以下疑问:
- 能否完全舍弃DTO类,仅用接口和Schema,在插入数据库时完成验证?
- 若不可行,有没有无需修改三处代码的替代方案?用DTO类替代接口是否可行?
最优实践方案
我已找到适合自身场景的最优方案,分享给遇到同类问题的开发者:
核心思路是:先定义描述模型的接口,使用@nestjs/mongoose的@Schema装饰器编写Schema类并实现该接口,同时保留实现同一接口的DTO用于请求验证。
针对特殊字段的处理规则:
- 若存在创建时无需传入但需存入数据库的字段,在接口中将其设为可选类型,DTO实现时直接忽略该字段;
- 若后续需要编辑这类字段,则将其添加到更新DTO中。
方案优势:修改接口时,DTO和Schema会通过类型检查报错提醒更新;多数项目中数据库迁移并不频繁,接口还能在代码其他场景复用。虽然仍需更新三个文件,但每个文件职责明确,是目前最优雅的解决方案。
代码示例
1. 定义模型接口
import { EventFormat } from '../enums'; interface IEvent { eventId: string; name: string; rank: number; format: EventFormat; } export default IEvent;
2. 编写Mongoose Schema类
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; import { HydratedDocument } from 'mongoose'; import IEvent from '~/shared_helpers/interfaces/Event'; import { EventFormat } from '~/shared_helpers/enums'; @Schema({ timestamps: true }) export class Event implements IEvent { @Prop({ required: true, immutable: true, unique: true }) eventId: string; @Prop({ required: true }) name: string; @Prop({ required: true }) rank: number; @Prop({ enum: EventFormat, required: true }) format: EventFormat; } // 数据库查询的返回类型 export type EventDocument = HydratedDocument<Event>; // 用于依赖注入的Schema实例 export const EventSchema = SchemaFactory.createForClass(Event);
3. 编写DTO类
创建事件DTO
import { IsEnum, IsNumber, IsString, Min, MinLength } from 'class-validator'; import IEvent from '~/shared_helpers/interfaces/Event'; import { EventFormat } from '~/shared_helpers/enums'; export class CreateEventDto implements IEvent { @IsString() @MinLength(3) eventId: string; @IsString() @MinLength(3) name: string; @IsNumber() @Min(0) rank: number; @IsEnum(EventFormat) format: EventFormat; }
更新事件DTO
import { PartialType } from '@nestjs/mapped-types'; import { CreateEventDto } from './create-event.dto'; export class UpdateEventDto extends PartialType(CreateEventDto) { // 如果接口中有创建时不需要传入的可选字段, // 若需要支持编辑,可在此处添加对应的验证逻辑 }
内容的提问来源于stack exchange,提问作者CodeToCode
相关产品推荐
相关产品推荐

