Reputation: 639
I have a DTO class of a user in NestJS. I am using many validations using class-validator package in order to enforce my logic. If a field that doesn't exists on the DTO definition, I would like to ignore it and even throw an error. This is why I was trying to use the 'excludeExtraneousValues' flag. When I do use it, it ignores all the fields, even the ones that defined in the DTO.
import { ApiPropertyOptional } from '@nestjs/swagger';
import {
IsDefined,
IsEmail,
IsOptional,
IsPhoneNumber,
MaxLength,
ValidateIf,
} from 'class-validator';
export default class UserDTO {
@ApiPropertyOptional()
@MaxLength(254)
@IsEmail()
@IsDefined()
@ValidateIf((object) => object.email || !object.phone_number)
email?: string;
@ApiPropertyOptional()
@MaxLength(15)
@IsPhoneNumber()
@IsDefined()
@ValidateIf((object) => object.phone_number || !object.email)
phone_number?: string;
@ApiPropertyOptional()
@IsOptional()
@MaxLength(40)
name?: string;
}
As I mentioned, I am using NestJS. This is the ValidationPipe definition:
app.useGlobalPipes(
new ValidationPipe({
transform: true,
stopAtFirstError: true,
transformOptions: { excludeExtraneousValues: true },
}),
);
Following the addition of 'excludeExtraneousValues' flag, I cannot send any value, even the ones that is defined.
Is it a bug or am I missing something?
Upvotes: 5
Views: 4299
Reputation: 1584
A bit old but I stumbled across and can see it was upvoted, so here goes:
I am wondering if you are mixed up on input vs. output. Your question isn't quite specific enough for me to be 100% sure. NestJS apps often make use of the class-validator and class-transformer libraries on both ends of the equation and can work on DTO's/entities that are dressed up with decorators from these libraries.
Pipes such as your ValidationPipe
are geared to the input side of things. Refer to the docs: https://docs.nestjs.com/techniques/validation.
Generally class-validator
is the key player on the input side, with class-transformer
only playing a role with applicable decorators like @Transform()
. To make use of class-transformer, you need to pass the transform: true
option as you do.
If you want to control behaviours regarding data fields coming into your ValidationPipe
that are not defined in your entity/DTO classes, take a look at the whitelist: boolean
, forbidNonWhitelisted: boolean
, and forbidUnknownValues: true
configuration options to satisfy your needs on the input side of things.
I have a feeling that once you check these options out, you will find that you will want to delete the transformOptions: { excludeExtraneousValues: true }
option.
On the output side of things is where interceptors come into play. Often in NestJS projects the included ClassSerializerInterceptor
is employed to serialize instances of DTO/entity classes to JSON for a response. Docs: https://docs.nestjs.com/techniques/serialization
This side is where you see more frequent use of class-transformer's decorators such as Exclude()
, Expose()
, and Transform()
.
This is also where you are probably more likely to find a use-case for a configuration option like excludeExtraneousValues
.
Suppose you had data in an object (e.g. from a database, file, or wherever) and wanted to populate a class (such as a DTO) so you could take advantage of these decorators, but only wanted to have certain fields actually sent back in the response, i.e. the ones that you explicitly specified and decorated in your class, and you didn't want to bother with Exclude()
and Expose()
decorators all over the place.
In such a case, the options for class-transformer may come in handy depending on what you want to do, e.g.
app.useGlobalInterceptors(new ClassSerializerInterceptor(app.get(Reflector), { excludeExtraneousValues: true }))
Upvotes: 10