#typescript #nestjs #class-validator
Вопрос:
У меня есть интерфейсное приложение, которое отправляет в мое серверное приложение запрос POST со следующим телом JSON
{
"principal": {
"name": "John Doe",
"birth": "1990-01-01T02:00:00.000Z",
"phone": "(12) 341 234 124",
"email": "test@test.com"
},
"companion": {
"name": "",
"birth": null,
"phone": "",
"email": ""
},
... // some other data
}
И в моем бэкэнд-приложении, которое я использую NestJS, поскольку и то, principal
и companion
другое имеют одинаковые свойства, я сопоставил со следующим DTO.
import { IsNotEmpty, IsString } from "class-validator";
export class NewDataDto {
principal: PersonDto;
companion: PersonDto;
// some other data
}
export class PersonDto {
@IsNotEmpty()
@IsString()
name: string;
birth?: Date;
@IsNotEmpty()
@IsString()
phone: string;
@IsNotEmpty()
@IsString()
email: string;
}
Таким образом, в principal
объекте все свойства обязательны, но в companion
объекте все свойства являются необязательными. Поскольку все свойства одинаковы в обоих объектах, изменяется только проверка, как я могу проверить это, используя один и тот же класс для обоих объектов?
Комментарии:
1. Вы пробовали github.com/typestack/class-validator#validating-nested-objects ?
2. Да, я пытался. Но у меня есть 2 объекта с разными проверками, которые относятся к одному и тому же классу , поэтому
name
, например, они должны быть обязательными вprincipal
, но могут быть пустыми вcompanion
.3. Как насчет создания отдельных классов для целей проверки?
4. Да, я согласен с Бруно, что лучше разделять занятия. А также взгляните на пакеты сопоставленных типов из nest js docs.nestjs.com/openapi/mapped-types
5. Да, это способ решить эту проблему. Но нарушает СУХОЙ принцип так сильно, что отбил у меня охоту следовать этому решению.
Ответ №1:
Итак, я нашел ответ на свою проблему. Действительно, есть способ сделать это. Не используя один и тот же класс, но не причиняя вреда СУХИМ участникам и повторно используя код. Я опубликую это здесь, чтобы это могло принести пользу кому-то, у кого такая же проблема.
export class PersonDto {
protected validateRequiredFields = false;
@ValidateIf((o) => o.validateRequiredFields || o.name)
@IsNotEmpty()
@IsString()
name: string;
birth?: Date;
@ValidateIf((o) => o.validateRequiredFields || o.phone)
@IsNotEmpty()
@IsString()
phone: string;
@ValidateIf((o) => o.validateRequiredFields || o.email)
@IsNotEmpty()
@IsString()
email: string;
}
export class PrincipalDto extends PersonDto{
constructor() {
super();
this.validateRequiredFields = true;
}
}
export class NewDataDto {
@ValidateNested()
@Type(() => PrincipalDto)
@IsDefined()
principal: PrincipalDto;
@ValidateNested()
@Type(() => PersonDto)
companion: PersonDto;
// some other data
}
Здесь следует отметить некоторые вещи.
Во-первых, если все классы находятся в одном файле, сначала необходимо объявить классы, которые не имеют зависимости.
Во-вторых, в поле @ValidateIf
вам нужно поместить validateRequiredFields
предложение с ИЛИ и поле, которое вы проверяете, потому что вы хотите проверить, имеет ли поле какое-либо значение.
В-третьих, при проверке материнского класса, в моем случае NewDataDto
, убедитесь, что вы проверяете @Type
правильно. И введите a @IsDefined
в свойство, которое вы хотите, чтобы необходимые поля были проверены.
И последнее, вы можете переопределить validateRequiredFields
внутренний конструктор или внешний, и у вас нет конструктора в подклассе, и это будет работать просто отлично. Но лично мне нравится переопределение в идее конструктора.