Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Validate Enum directly in controller function

I have a query parameter in my REST API, which values should be restricted by an enum type. I'm looking for a way to throw a "Bad Request" error, when a client gives something different.

My enum looks like this:

export enum Precision {
    S = 's',
    MS = 'ms',
    U = 'u',
    NS = 'ns',
}

My controller function looks like this:

  @Get(':deviceId/:datapoint/last')
  @ApiOkResponse()
  @ApiQuery({name: 'precision', enum: Precision})
  getLastMeasurement(
    @Param('deviceId') deviceId: string,
    @Param('datapoint') datapoint: string,
    @Query('precision') precision: Precision = Precision.S,
    @Res() response: Response,
  ) {
    console.log(precision);
    ....
    response.status(HttpStatus.OK).send(body);
  }

My problem here is that the function accepts other values, too (for example I can send an f as the query parameter's value). The Function won't return an error to the client, but I want to without writing an if else block at the beginning of each controller function.
I guess there is a rather simple solution to this, but when I try to look it up on the internet I always get results for class validation in DTOs, but not for a simple enum validation directly in the query param/REST controller.

Thanks for your time,
J

like image 227
JWo Avatar asked Apr 15 '26 07:04

JWo


1 Answers

There is 2 issues here.

The first one is that you are passing the default value of precision params in the wrong way. You must use the DefaultValuePipe like this:

getLastMeasurement(
  ... // some other params
    @Query('precision', new DefaultValuePipe(Precision.S)) precision: Precision
  ) { 
  ... // do something
}

The second one is the enum validation. NestJS comes with only 6 types of validationPipes and none of them validates an enum, so you must create your own custom validation pipe to validate enums.

There is 2 possible ways that you can do that:

  1. Create a custom pipe to validate only your specific enum;
  2. Create a custom pipe generic to validate any enum;

Based on this https://docs.nestjs.com/pipes#custom-pipes, it would be something like:

  1. Validate only the specific enum
import { BadRequestException, PipeTransform } from '@nestjs/common';
import { isDefined, isEnum } from 'class-validator';

export class PrecisionValidationPipe implements PipeTransform<string, Promise<Precision>> {

  transform(value: string): Promise<Precision> {
    if (isDefined(value) && isEnum(value, Precision)) {
      return Precision[value];
    } else {
      const errorMessage = `the value ${value} is not valid. See the acceptable values: ${Object.keys(
        Precision
      ).map(key => Precision[key])}`;
      throw new BadRequestException(errorMessage);
    }
  }
}

and then in your request, it would be like

  getLastMeasurement(
    @Query('precision', PrecisionValidationPipe, new DefaultValuePipe(Precision.S)) precision: Precision,
  ) {
    console.log(precision);
    ....
    response.status(HttpStatus.OK).send(body);
  }
  1. Validate any enum (my favorite)
import { BadRequestException, Injectable, PipeTransform } from '@nestjs/common';
import { isDefined, isEnum } from 'class-validator';

@Injectable()
export class EnumValidationPipe implements PipeTransform<string, Promise<any>> {
  constructor(private enumEntity: any) {}
  transform(value: string): Promise<any> {
      if (isDefined(value) && isEnum(value, this.enumEntity)) {
        return this.enumEntity[value];
      } else {
        const errorMessage = `the value ${value} is not valid. See the acceptable values: ${Object.keys(this.enumEntity).map(key => this.enumEntity[key])}`;
        throw new BadRequestException(errorMessage);
      }
  }
}

and then in your request, it would be like

  getLastMeasurement(
    @Query('precision', new EnumValidationPipe(Precision), new DefaultValuePipe(Precision.S)) precision: Precision,
  ) {
    console.log(precision);
    ....
    response.status(HttpStatus.OK).send(body);
  }
like image 126
Raphael Soares Avatar answered Apr 19 '26 10:04

Raphael Soares



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!