The validation decorators (@ValidateNested() and @Type(() => KeyDto)) only work on actual objects, not strings and that is not working because NestJS treats query parameters as strings and does not automatically deserialize them into objects.
Since you don't want to use @Transform, the best option is to manually handle the transformation inside a custom Pipe.
import { PipeTransform, Injectable, ArgumentMetadata, BadRequestException } from '@nestjs/common';
import { plainToInstance } from 'class-transformer';
import { validate } from 'class-validator';
@Injectable()
export class ParseJsonPipe implements PipeTransform {
async transform(value: any, metadata: ArgumentMetadata) {
if (!value) return value;
try {
// Parse the JSON string into an object
const parsed = JSON.parse(value);
// Convert to the expected class
const object = plainToInstance(metadata.metatype, parsed);
// Validate the transformed object
const errors = await validate(object);
if (errors.length > 0) {
throw new BadRequestException('Validation failed');
}
return object;
} catch (error) {
throw new BadRequestException('Invalid JSON format');
}
}
}
And then apply the Pipe in the controller:
@Get()
getSomething(@Query('key', new ParseJsonPipe()) key: KeyDto) {
console.log(key); // This should now be an object
}