Search code examples
nestjsclass-validator

NestJS: Is it possible to reuse same DTO validation with different field names?


It can be noticed that validating bodies and even route/query params can be much simpler, safer and more readable when you use a DTO instead of, for example, a pipe (depending on the case). As a simple example, I like the idea of using a DTO for validation of the id, like in a findOne() route. So, with a class like this

export class IdDto {
  @IsInt()
  @IsPositive()
  id: number;
}

I can have great validation of the (serial) id. And use it in the route handler like this

findOne(@Param() { id }: IdDto)

The problem is when I have, for example, multiple ids as route params. Obviously I have to name them in a different manner, and then I cannot use this DTO anymore. Unless I create a specific DTO for every case like this one, just renaming the fields. Would there be any way to maintain the usage of this DTO (or any other) in situations like these? Or is there really no alternative?

Of course, I could build my own pipe. It's just that the DTO approach is much simpler, and also class-validator decorators automatically show exactly what step of validation failed. But maybe it's the only option, apart from multiple similar DTOs.

Thanks in advance, and best regards.

P.S.: In the case of multiple ids, that I mentioned, it is a bit more complex. But in the case that I still have just a single id, but want to name it differently in the route? The same question applies, in case it may be simpler.


Solution

  • Generally, decorators on dynamic fields in Typescript doesn't really work because there's no field to (easily) bind to at compile time.

    Rather than changing the name of the field, if you are looking for a way to better manage the same decorators across different classes, you could use decorator composition and the applyDecorators method to create a single decorator like

    export const IdValidator = applyDecorators(
      IsInt(),
      IsPositive(),
    );
    

    And now use @IdValidator() instead of the others. You still have to make multiple classes, but now have a single source for the entire set of decorators for id validation.