Following on from This question, I have created an interceptor, and I am able to map my parameters into my DTO. However, the number parameters, are not being converted to numeric during the validation.
The DTO:
export class GetDTO {
@IsDefined() @IsNumber() @Max(50) @Min(1) @Type( () => Number) public Start: number;
@IsDefined() @IsString() @MaxLength(64) @MinLength(5) public Description: string;
Controller defines the local copy of the interceptor
@UseInterceptors(AddParametersToRequestBodyInterceptor)
export class MyController {
@Post('/:Start')
public async GetData(
@Param('Start', ParseIntPipe) Start: number,
@Body() Data: GetDTO
): Promise<ResponseDTO> {
}
When debugging this, I can see it works as it takes the Start parameter from the URL (POST /25
), and does add it into the request body, and replaces the value with a string '25' (or adds it if it is not in the request body).
import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common';
import { Observable } from 'rxjs';
@Injectable()
export class AddParametersToRequestBodyInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
const req = context.switchToHttp().getRequest();
const { params, body } = req; // get the params and body from req
const NewRequestBody = { ...body, ...params }; // moves the params to the body, replacing matching data
req.body = NewRequestBody; // just to be safe. I believe you could omit this, but rather safe than sorry
return next.handle(); // keep the request going
}
}
So far so good. The ValidationPipe is global, with the whitelist: true and transform: true options.
ValidationPipeOptions = {
transform: true,
whitelist: true, // strip unknown fields
};
Setting up a local ValidationPipe with the same options does not help. The validation still sees the Start as a string.
"Start must not be less than 1",
"Start must not be greater than 50",
"Start must be a number conforming to the specified constraints"
Debug payload shows:
Description: 'Testing',
Start: '25'
Where Description was passed in the request body, so the interceptor is combining the data.
EDIT I can modify the interceptor to determine if the field in the body is numeric with something like:
intercept(context: ExecutionContext, next: CallHandler): Observable<any>
{
const req = context.switchToHttp().getRequest();
const { params, body } = req; // get the params and body from req
// Process through parameters checking values in request body
for (const ParameterName in params) {
if (typeof body[ParameterName] === 'number') {
const Value: number = parseInt(params[ParameterName], 10);
params[ParameterName] = Value;
}
}
const NewRequestBody = { ...body, ...params }; // moves the params to the body
req.body = NewRequestBody; // just to be safe. I believe you could omit this, but rather safe than sorry
return next.handle(); // keep the request going
}
However, this only works in the values are in the request body. I still need to determine how to convert these for the validation with the @Type(()=>Number)