I am trying to use @Expose with an alias name for properties of a class as below but I am getting the response in camelCase.
import { Expose } from 'class-transformer';
import { BaseResponse } from './base-response.class';
export class ValidationResponse extends BaseResponse {
@Expose({
name: 'SomeField',
})
someField: string;
@Expose({
name: 'AnotherField',
})
anotherField= string;
}
I am throwing a bad request error as below with ValidationResponse from a validation pipe in case of payload validation failure as below.
Bad request error class
import { HttpException, HttpStatus } from '@nestjs/common';
export class BadRequestError extends HttpException {
constructor(response?: unknown) {
super(response, HttpStatus.BAD_REQUEST);
}
}
Custom validation pipe
import { ArgumentMetadata, Inject, PipeTransform, UseInterceptors, ClassSerializerInterceptor } from '@nestjs/common';
import { plainToClass } from 'class-transformer';
import { validate } from 'class-validator';
import { BadRequestError } from '../exceptions/bad-request.exception';
import { ErrorModel } from '../../common/classes/error-model.class';
import { ErrorCode } from '../../common/enums/error.enum';
import { ValidationResponse } from '../../common/classes/validation-response.class';
import { REQUEST } from '@nestjs/core'
import { CustomRequest } from 'src/common/classes/custom-request.class';
@UseInterceptors(ClassSerializerInterceptor)
export class CustomValidationPipe implements PipeTransform {
constructor(@Inject(REQUEST) protected readonly request: CustomRequest) { }
async transform(value: any, { metatype }: ArgumentMetadata) {
const object = plainToClass(metatype, value);
const errors = await validate(object, {
forbidUnknownValues: false,
});
if (errors.length) {
let errorResponse: ValidationResponse = new ValidationResponse();
errorResponse.someField= 'somevalue';
errorResponse.anotherField= 'anothervalue';
throw new BadRequestError(errorResponse);
}
return value;
}
}
I am using the validation pipe in controller for a POST API as below
import { CustomValidationPipe } from 'custom-validation.pipe';
@UseInterceptors(ClassSerializerInterceptor)
export class SomeController {
@Post('test')
@HttpCode(200)
@ApiCreatedResponse({
type: SomeResponse,
})
async someFunction(
@Request()
request,
@Body(CustomValidationPipe)
body: SomeRequest,
): Promise<SomeResponse> {
// controller logic here
}
}
With @Expose I am trying to change the casing of the fields to pascal case but when I get the response from the pipe it is in camel case as the field are originally defined in ValidationResponse class. Maybe I am doing something wrong. Any help is really appreciated.
The
ClassSerializerInterceptor
only works on returned values from thecontroller
, not errors/exceptions or anythingthrown
, at least by default. If you want to add that, you'd have to extend the class and add a way to.catchError()
for when that happens. It would be easier for you to just set theValidationResponse
class to have these pascal case fields you want it to and set them directly when throwing the exception.Also as a side note, the
@UseInterceptors()
does nothing on the pipe custom pipe class. It only effects the controller here, so you can get rid of it.