Какова наилучшая практика в отношении DTO, схемы или интерфейса для ввода в typescript

#typescript #nestjs

#typescript #nestjs

Вопрос:

В настоящее время в моем коде typescript (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;
}
 

Пример использования :

  • в контроллере с dto
 async createUser(@Body() user: UserDto): Promise<UserSchema> {
  const nameAlreadyExist = await this.userService.getUserByField('name', user.name);
  if (nameAlreadyExist amp;amp; 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();
}
 

Ответ №1:

Шаблон DTO полезен в контексте NestJS, потому что, когда вы используете реальные классы, вы можете применять декораторы, чтобы иметь возможность проверять запросы на границе вашего API.

Схемы — это концепция Mongo, и они необходимы для обеспечения возможности чтения и записи из базы данных. Если существует полное перекрытие между схемой и DTO, вы могли бы рассмотреть возможность объединения их в один класс и объединения их декораторов. Однако обычно считается хорошей практикой иметь отдельное представление ваших моделей, отличное от DB, которое обрабатывается на уровне API.

Интерфейсы — это общая функция языка TypeScript, позволяющая описывать форму данных. Они очень полезны внутри кода библиотеки, когда вы хотите обеспечить безопасность во время компиляции внутри кода, который вы контролируете. Как только вы окажетесь внутри уровня обслуживания, если вам не нужны декораторы, вы всегда можете обратиться к интерфейсам или типам для обеспечения безопасности типов.

На ваш вопрос нет единственно правильного ответа. Это всегда будет зависеть от потребностей вашего приложения, но в целом я думаю, что хорошей структурой для подражания является:

  • DTO на границе API для проверки сообщений, поступающих из других систем
  • Модели схемы / БД на вашем уровне обслуживания, позволяющие взаимодействовать с базой данных отдельно от ваших контроллеров
  • Интерфейсы / типы для всего внутреннего кода библиотеки, который не требует декораторов