Reputation: 358
Yo, i have store application with nestjs, i need validate mongo id, which is pass by query, the problem is that i also pass and search query. I write pipe which validate all values, and exclude this search query
@Injectable()
export class ValidationObjectId implements PipeTransform {
transform(value: UniqueId, metadata: ArgumentMetadata) {
if (
!Types.ObjectId.isValid(value) &&
metadata.data !== "searchString"
) {
throw new BadRequestException("Неверный параметр запроса");
}
return value;
}
}
But this code not reusable for other case. I want get some examples, how i can do this
Upvotes: 21
Views: 67862
Reputation: 5066
For single query param usage, you can play with this example:
import { ArgumentMetadata, BadRequestException, Injectable, PipeTransform } from '@nestjs/common';
type TOptional<T> = T | undefined;
@Injectable()
export class ValidateEnum<T extends Record<string, unknown>> implements PipeTransform<T> {
constructor(public readonly enumObj: T, public readonly isRequired = false) {}
async transform(value: TOptional<T>, { data: argName }: ArgumentMetadata): Promise<TOptional<T>> {
const withValidation = this.isRequired ? true : value !== undefined;
if (withValidation) {
const enumValues = Object.values(this.enumObj);
if (!enumValues.includes(value)) {
throw new BadRequestException(`Invalid ${argName}=${value} - possible values: ${enumValues.join('|')}`);
}
}
return value;
}
}
If you want to use a pipe with a DTO object, check this out:
import { ArgumentMetadata, Injectable, PipeTransform } from '@nestjs/common';
import { plainToInstance, Type } from 'class-transformer';
import { IsInt, IsOptional } from 'class-validator';
export class PaginationRequestDto {
@Type(() => Number)
@IsInt()
@IsOptional()
public readonly page?: number;
@Type(() => Number)
@IsInt()
@IsOptional()
public readonly take?: number;
}
@Injectable()
export class PaginationTransformPipe implements PipeTransform {
async transform(dto: PaginationRequestDto, { metatype }: ArgumentMetadata) {
if (!metatype) {
return dto;
}
return plainToInstance(metatype, dto);
}
}
And usage example:
@Get('')
// @UsePipes(new PaginationTransformPipe()) // also possible
public async someOperation(
@Query(new PaginationTransformPipe()) pagination: PaginationRequestDto,
@Query('status', new ValidateEnum(ESomeEnum)) status?: ESomeEnum
) {
// ...your logic
}
For someone, it can be helpful to use default pipes
Upvotes: 2
Reputation: 1065
The cleanest and most reusable approach would probably be to make use of the ValidationPipe
with a Query-DTO-Class.
Take a look at the following example.
Inside the Controller you can pass a Pipe to the @Query()
-Decorator.
You can use the ValidationPipe
which already comes with Nest and makes use of the class-validator
and class-transformer
Packages.
You can create a DTO-Class for your Query-Parameters as done in the PostHelloQuery.dto.ts from my example.
import { IsBoolean, IsOptional } from "class-validator";
export class PostHelloQueryDTO {
@IsOptional()
@IsBoolean()
public useExclamation?: boolean;
}
Here you define constraints for your Data using decorators from class-validator
. For a list of all decorators, please refer to https://github.com/typestack/class-validator#validation-decorators .
If none of the validators fit your needs you can also create your own Decorator as shown here.
In my example, the useExclamation
-Query Param is an optional boolean.
Note that incoming query parameters are parsed as strings.
The conversion is done using the enableInplicitConversion
-Option as seen in the Controller:
@Query(new ValidationPipe({
transform: true,
transformOptions: {enableImplicitConversion: true},
forbidNonWhitelisted: true
})) query: PostHelloQueryDTO
For more information about using ValidationPipe
with class-validator
, you can take a look at the NestJS Documentation:
https://docs.nestjs.com/techniques/validation
For your specific Use-Case (Validating MongoDB IDs), I have found an open Issue with an Example Implementation for a @IsMongoDB
-Decorator:
https://github.com/typestack/class-validator/issues/630#issuecomment-645638436
Upvotes: 50