首页 > 解决方案 > 输入打字稿的 DTO、模式或接口的最佳实践是什么

问题描述

目前在我的打字稿代码(nestjs)中,我使用控制器中的 DTO 来验证进入我的 API 的数据,模式用作其余文件中的类型,并且我不创建接口,除非在特殊情况下。

我试图弄清楚我在做什么是好的,或者我是否应该在任何地方使用 DTO 作为一种类型,或者什么?目标是提高我的代码质量。

用户集合示例:

user.schema.ts

import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';

@Schema({ collection: 'users' })
export class User extends Document {
  @Prop()
  name: string;
}

export const UserSchema = SchemaFactory.createForClass(User);
UserSchema.set('timestamps', true);

user.dto.ts

import { IsNotEmpty, IsString, Length } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';

export class UserDto {
  @IsNotEmpty()
  @IsString()
  @Length(3)
  @ApiProperty({ required: true })
  readonly name: string;
}

使用示例:

async createUser(@Body() user: UserDto): Promise<UserSchema> {
  const nameAlreadyExist = await this.userService.getUserByField('name', user.name);
  if (nameAlreadyExist && nameAlreadyExist.length > 0) {
    throw new ConflictException(getErrorObject(ErrorCodeEnum.duplicate, EntityCodeEnum.user, ['name']));
  }
  return this.userService.createUser(user as UserSchema);
}
async createUser(user: UserSchema): Promise<UserSchema> {
  const newUser = new this.UserModel(user);
  return newUser.save();
}

标签: typescriptnestjs

解决方案


DTO 模式在 NestJS 的上下文中很有用,因为当您使用实际的类时,您可以应用装饰器来验证 API 边界的请求。

Schemas 是 Mongo 的概念,是实现从数据库读取和写入所必需的。如果 Schema 和 DTO 之间完全重叠,您可以考虑将它们合并到一个类中并组合它们的装饰器。但是,在 API 层处理模型的单独非 DB 表示通常被认为是一种好的做法。

接口是一种通用的 TypeScript 语言功能,用于描述数据的形状。当您想在您控制的代码中强制编译时安全时,它们在库代码中非常有用。一旦你进入服务层,如果你不需要装饰器,你总是可以使用接口或类型来提升类型安全性。

你的问题没有一个正确的答案。它总是取决于您的应用程序的需求,但总的来说,我认为一个好的结构是:

  • API 边界的 DTO 用于验证来自其他系统的消息
  • 服务层中的模式/数据库模型,以实现与控制器分开的数据库交互
  • 不需要装饰器的所有内部库代码的接口/类型

推荐阅读