I'm trying to make use of Nest JS Validation Pipe to auto transform and validate my GET Request Query Params
e.g
{{url}}/path?param-one=value¶m-two=value
On app.module.ts
, I have the following code to set global validation pipe
app.useGlobalPipes(
new ValidationPipe({
transform: true,
whitelist: true,
forbidNonWhitelisted: true,
}),
);
And I have a DTO to do the validation
class MyValidationDto {
@IsString()
paramOne: string
@IsString()
paramTwo: string
}
And in my controller, I make use of the MyValidationDto
class
class MyController {
... stuff
@Get('/path')
async myFunction (Query() queryParams: MyValidationDto) { ...code }
}
However, I'm not sure where to go to in order to parse the kebab case query keys param-one
and param-two
to the camelCase class properties paramOne
and paramTwo
in the validation DTO
I've tried looking at Nest JS doc, class-validator
doc and class-transformer
doc, as well as search the highs and lows of internet to no luck. This should be a fairly common case so not sure where I'm going wrong here
Unless this is not possible and I should be using the Query()
decorator instead. Please advise :pray:
TLDR; There's no native method from NestJS or class-validator to do this for now (a similar feature request is still open on CT repo).
However, there are a couple of workarounds:
You can use @Expose()
but you still need to customize your error message as the new exposed name won't be passed to the context:
export class SomeDTO {
@IsString()
@Expose({ name: 'my-name' })
myName: string;
..
Or you can create a NestJS pipe that normalizes your query params before they hit your controller.
For example, create a new pipe:
@Injectable()
export class NormalizeQueryParamsPipe implements PipeTransform {
transform(value: RestaurantDTO, metadata: ArgumentMetadata) {
const normalizedQueryParams = {
...value,
name: value['my-name'],
};
delete normalizedQueryParams['my-name'];
return normalizedQueryParams;
}
}
Of course, you may do better than renaming attributes manually and using an approach like this combined with this: Basically use class validator methods combined with a transformer that converts your kebab-case keys to camelcase (e.g plainToClass(camelcaseKeys(value), MyValidationDto)
)
This transforms your 'my-name'
to myName
, and you want to have this before the global validation pipe:
// in main.ts:
app.useGlobalPipes(new NormalizeQueryParamsPipe());
app.useGlobalPipes(new ValidationPipe());
// or: app.useGlobalPipes(new NormalizeQueryParamsPipe(), new ValidationPipe());
In case you are not using a global validation pipe, you can just use @UsePipes()
in your controller:
@Get()
@UsePipes(new NormalizeQueryParamsPipe())
async getAll() {
..