When working with controllers sometimes it would be nice to provide a default value for some parameters (i.e. boolean flags).
One might assume that it is possible to do so by providing default values for function parameters, like:
@Controller('/foo')
export class FooController {
@Get()
async getMany(
@Res() res: Response,
@Query('activeOnly', ParseBoolPipe) activeOnly = false,
): Promise<void> {
// ...
}
}
Due to the implementation of primitive pipes (i.e. _ParseBoolPipe_, _ParseIntPipe_) this unfortunately would result in an error, as the decorated function's default value is applied after the pipes are done with the params and primitive pipes result in an error upon recieving an _undefined_ value.
I propose an addition of a _DefaultValuePipe_ to the roster of Nest's built-in pipes.
It would be used like:
@Controller('/foo')
export class FooController {
@Get()
async getMany(
@Query('activeOnly', new DefaultValuePipe(false), ParseBoolPipe) activeOnly: boolean,
@Res() res: Response,
): Promise<void> {
// ...
}
}
Nothing to add here, I think.
When working with Nest came upon this problem and had to write such a solution for myself, would like to share with the Nest community.
Sounds reasonable, I like it! Would you like to create a PR for this issue?
Yup, sure - will do so :)
Believe my issue is related to this as well https://github.com/nestjs/nest/issues/4682
Merged & published as a part of the latest release.
@apatryda sorry mate, do you know if this new pipe have issues with this configuration?
app.useGlobalPipes(
new ValidationPipe({
transform: true,
whitelist: true,
forbidNonWhitelisted: true
})
)
I'm getting this bad response:
{
"statusCode": 400,
"message": "Validation failed (numeric string is expected)",
"error": "Bad Request"
}
when the query params are empty:
async findAll(
@Query(
'search',
new DefaultValuePipe('')
) search: string,
@Query(
'offset',
new DefaultValuePipe(0),
ParseIntPipe
) offset: number,
@Query(
'limit',
new DefaultValuePipe(10),
ParseIntPipe
) limit: number
): Promise<Array<User>> {
const users = await this.userService.findByRoleIds(
[DefaultRole.Admin, DefaultRole.User],
search,
offset,
limit
)
return users
}
Code here https://github.com/proyecto26/MyAPI/blob/master/src/controllers/user.controller.ts#L85
Thanks in advance, I'm creating a template as you can see :)
Seems like the global ValidationPipe
is executed before the pipes in the @Query()
decorator. I've got what I believe is the same problem.
Global ValidationPipe
with transform:
app.useGlobalPipes([new ValidationPipe({ transform: true, whitelist: true })]);
A DTO:
export class CoordinatesDto {
@IsNotEmpty()
public latitude: string;
@IsNotEmpty()
public longitude: string;
}
A custom pipe for transforming the string to the DTO:
@Injectable()
export class ParseCoordinatesPipe implements PipeTransform {
transform(value: string): CoordinatesDto {
const [lat, lng] = value.split(',');
const coordinates = new CoordinatesDto();
coordinates.latitude = lat;
coordinates.longitude = lng;
return coordinates;
}
}
Used the following way:
@Query('coordinates', new DefaultValuePipe('0,0'), ParseCoordinatesPipe) coordinates?: CoordinatesDto
Results in:
{
"statusCode": 400,
"message": [
"latitude should not be empty",
"longitude should not be empty"
],
"error": "Bad Request"
}
Only by disabling the global ValidationPipe
and adding the ValidationPipe
to the @Query()
, things work as expected.
@jdnichollsc Did you ever get this working using a global ValidationPipe?
@joakimbugge I think yes, but let me try your example, thanks mate!
I have another demo using that template here: https://github.com/jdnichollsc/adventure-closure
Any pull request to any of these projects are really appreciated! <3
That's the expected run order, according to how pipes are bound, global, then controller, then method, then parameter. It's documented here
Most helpful comment
@apatryda sorry mate, do you know if this new pipe have issues with this configuration?
I'm getting this bad response:
when the query params are empty:
Code here https://github.com/proyecto26/MyAPI/blob/master/src/controllers/user.controller.ts#L85
Thanks in advance, I'm creating a template as you can see :)