papillon
papillon

Reputation: 2063

No metadata found for class-validator

I am trying to use a ValidationPipe but no matter how I write my code I get the following warning when sending a request: No metadata found. There is more than once class-validator version installed probably. You need to flatten your dependencies.

My route looks something like this:

@Get()
@UsePipes(new ValidationPipe({ transform: true }))
async findAll(@Query() queryDto: QueryDto) {
    return await this.myService.findAll(queryDto);
}

And my DTO looks something like this:

export class queryDto
{
    @ApiModelProperty({
        description: 'Maximum number of results',
        type: Number,
        example: 50,
        default: 50,
        required: false
    })
    readonly limit: number = 50;
}

I tried using the ValidationPipe several ways, following the doc, but nothing works for me. I know it does not work because although the request gets a response, the default value that I wrote in my DTO for the property limit, which is 50, is not used when the query is empty. Therefore, when no limit is provided in the query, limit's value is undefined, whereas it should be 50 (which means the ValidationPipe is not used).

My package.json seems correct:

npm ls class-validator
[email protected] /home/pierre_t/Bureau/dev/ApiSport
└── [email protected]

Full package.json:

{
  "name": "api-sport",
  "version": "0.0.1",
  "description": "",
  "author": "",
  "license": "MIT",
  "scripts": {
    "build": "tsc -p tsconfig.build.json",
    "format": "prettier --write \"src/**/*.ts\"",
    "start": "ts-node -r tsconfig-paths/register src/main.ts",
    "start:dev": "nodemon",
    "start:debug": "nodemon --config nodemon-debug.json",
    "start:prod": "pm2 start ./src/main.js --no-daemon",
    "lint": "tslint -p tsconfig.json -c tslint.json",
    "test": "jest",
    "test:watch": "jest --watch",
    "test:cov": "jest --coverage",
    "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
    "test:e2e": "jest --config ./test/jest-e2e.json"
  },
  "dependencies": {
    "@nestjs/common": "^6.0.5",
    "@nestjs/core": "^6.0.5",
    "@nestjs/platform-express": "^6.0.5",
    "@nestjs/swagger": "^3.0.1",
    "@nestjs/typeorm": "^6.0.0",
    "@types/lodash": "^4.14.123",
    "class-transformer": "^0.2.0",
    "class-validator": "^0.9.1",
    "dotenv": "^7.0.0",
    "hbs": "^4.0.3",
    "mysql": "^2.16.0",
    "pm2": "^3.4.1",
    "reflect-metadata": "^0.1.12",
    "rimraf": "^2.6.2",
    "rxjs": "^6.3.3",
    "swagger-ui-express": "^4.0.2",
    "typeorm": "^0.2.16"
  },
  "devDependencies": {
    "@nestjs/testing": "^6.0.5",
    "@types/express": "^4.16.0",
    "@types/jest": "^23.3.13",
    "@types/node": "^10.14.4",
    "@types/supertest": "^2.0.7",
    "jest": "^23.6.0",
    "nodemon": "^1.18.9",
    "prettier": "^1.15.3",
    "supertest": "^3.4.1",
    "ts-jest": "^23.10.5",
    "ts-node": "^7.0.1",
    "tsconfig-paths": "^3.7.0",
    "tslint": "5.12.1",
    "typescript": "^3.4.1"
  },
  "jest": {
    "moduleFileExtensions": [
      "js",
      "json",
      "ts"
    ],
    "rootDir": "src",
    "testRegex": ".spec.ts$",
    "transform": {
      "^.+\\.(t|j)s$": "ts-jest"
    },
    "coverageDirectory": "../coverage",
    "testEnvironment": "node"
  }
}

Why do I get this message and how can I use ValidationPipe?

Upvotes: 12

Views: 12528

Answers (4)

Walkance
Walkance

Reputation: 392

I will share here a solution for another situation which provokes the same error. (Error comes from class-validator package as mentioned above, 0.14.1 version in my case)

If you import only the typescript type of DTO class and use it with a nest param decorator (@Body, @Query etc.), you will get the same error:

/** this fails */
import {Body} from '@nestjs/common';
import type {CreatePageDto} from './pages/dto/create-page.dto';

createPage(@Body() pageDto: CreatePageDto) { ... }

class-validator use reflection to access class constructor, so you need to remove 'type' in the CreatePageDto import:

/** this works */
import {Body} from '@nestjs/common';
import {CreatePageDto} from './pages/dto/create-page.dto';

createPage(@Body() pageDto: CreatePageDto) { ... }

It is not obvious from the text of this error message, so I hope it helps someone.

Upvotes: 0

matt
matt

Reputation: 625

This is my bootstrap, it works with class-validator:

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalPipes(new ValidationPipe());
  await app.listen(3000);
}
bootstrap();

Upvotes: 0

Mathiasfc
Mathiasfc

Reputation: 1697

The question has already been answered, but for future reference of people with the same problem...

The class-validator allows you to bypass the validation of certain property (whitelisting) special flags to validate any property.

As the docs:

This will strip all properties that don't have any decorators. If no other decorator is suitable for your property, you can use @Allow decorator

e.g:

import {validate, Allow, Min} from "class-validator";

export class Post {

    @Allow()
    title: string;

    @Min(0)
    views: number;

    nonWhitelistedProperty: number;
}

Upvotes: 1

Kim Kern
Kim Kern

Reputation: 60357

This is because you are using class-validator but without any validations, see this issue:

Basically, it warns that you don't have any metadatas in the storage, which means you haven't used any decorator from class-validator. That means you don't perform any validation, so you should just pass validate: false option to buildSchema to disable automatic validation.

I'm not sure if you can turn of validation for nest's ValidationPipe, but alternatively you can just add an assertion to your dto (if it makes sense), e.g.:

import { Min } from 'class-validator';
export class QueryDto {
    @Min(1)
    readonly limit: number = 50;
}

By the way: Since your @Query will only have string properties, you'll probably want to transform your limit from string to number. Have a look at this answer.

Upvotes: 16

Related Questions