'How to pass default parameters to the @Query class in Nest.Js?

I'm trying to pass the default parameters maxnodes=3 and addstats=false to the controller via the @Query parameter in Nest.Js.

The code works fine, but the default parameters are not used. When I pass on the query parameters the ones that are passed are shown, but if none are passed, the default values (3 and false) are not used.

How to fix that?

context.contructor.ts:

import { CreateContextQuery } from './context.query';
import { CreateContextDto } from './context.dto';

@Post('graph')
  public async createGraphForContext(
    @Body('context') contextData: CreateContextDto,
    @Query()
    contextQuery: CreateContextQuery,
  ) {
    const before = Date.now();

    const { context } = await this.contextService.createContext(contextData);

    const graph = await this.contextService.getGraphOfContext(
      context.id,
      contextQuery.maxnodes,
      contextQuery.addstats,
    );

}

context.query.ts:

import { ApiProperty } from '@nestjs/swagger';

export class CreateContextQuery {
  @ApiProperty({
    description: 'Maximum number of nodes to show on the graph',
  })
  maxnodes;
  @ApiProperty({
    description: 'Include graph statistics',
  })
  addstats;
  constructor(maxnodes = 3, addstats = false) {
    this.maxnodes = maxnodes;
    this.addstats = addstats;
  }
}



Solution 1:[1]

What you receive in the query param is a plain object. You can achieve what you want putting a pipe in your query param and applying a class transform to instantiate the class.

Solution 2:[2]

Read this: https://docs.nestjs.com/pipes#providing-defaults

contextQuery isn't an instance of CreateContextQuery because, without any configuration, Nest won't call new CreateContextQuery any time. This is why you end up using pipes (read this https://docs.nestjs.com/techniques/validation#transform-payload-objects)

Solution 3:[3]

So basically in your DTO, you can give default values.

export class CreateContextQuery {
  @IsOptional()
  @Type(() => Number)
  @IsNumber()
  @Min(0)
  maxnodes?: number = 3;

  @IsOptional()
  @Type(() => Boolean)
  @IsBoolean()
  addstats?: boolean = false;

  constructor(maxnodes = 3, addstats = false) {
    this.maxnodes = maxnodes;
    this.addstats = addstats;
  }
}
// as you can see i am using validation too

And in your controller :

  @Post('graph')
  @UsePipes(new ValidationPipe({ transform: true })) 
// you need to add this for tansformation
  public async createGraphForContext(
    @Body('context') contextData: CreateContextDto,
    @Query()
    contextQuery: CreateContextQuery,
  ) {
    const before = Date.now();

    const { context } = await this.contextService.createContext(contextData);

    const graph = await this.contextService.getGraphOfContext(
      context.id,
      contextQuery.maxnodes,
      contextQuery.addstats,
    );

}

PS

Also if you want you can add custom decorators, in your case: // add this decorator

export const GetContextQuery = createParamDecorator((_data: unknown, ctx: ExecutionContext): CreateContextDto => {
  const request = ctx.switchToHttp().getRequest();
  const query = request.query;

  const maxnodes = parseInt(query.maxnodes) || 3;//default values here in case it fails to parse
  const addstats = Boolean(query.addstats) || 0;
  return { addstats, addstats };
});

and in your controller, you can call the decorator instead of @Query just add your decorator @GetContextQuery() context: CreateContextDto, and now you do not need the UsePipes

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Lazt Omen
Solution 2 Micael Levi
Solution 3