question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Dependency injection with class-validator

See original GitHub issue

I’m submitting a…


[ ] Regression 
[ ] Bug report
[ ] Feature request
[x ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.

Current behavior

As mentioned in the documention NestJS is supposed to works well very with class validator, however i’m not successful trying to implement a custom validation class ( https://github.com/typestack/class-validator#custom-validation-classes ) or decorator. This usecase is more than usefull to implement complex validation logic that require injecting services As its a pretty standart usecase, i guess that there is a way to do it, but i’m not able to find it! could be a great addition to the online documentation imo !

Expected behavior

I’ve tried to add my Validator class as a component but not working. In the class-validator documentation they mentioned that we can register a DI, is this doable with Nest ?

Minimal reproduction of the problem with instructions

@Controller('cars')
export class CarController {

    @Get()
    public test(@Res() res) {
        const dto = new CarInsertDTO();
        dto.brand = 'toyota';

        validate(dto).then(errs => {
            if (errs && errs.length > 0) {
                throw new BadRequestException(errs);
            }

            res.send(200);
        });
    }
}

export class CarInsertDTO {
    @IsString()
    public name: string;

    @Validate(BrandValidator, { message: 'Invalid brand'})
    public readonly strategy;
}


@ValidatorConstraint()
export class BrandValidator implements ValidatorConstraintInterface {
    constructor(private readonly brandService: BrandService) {}

    validate(brandName: any, args: ValidationArguments) {
        // can be a http service , database service or whatever
        const brands: string[] = this.brandService.all();

        return brands.indexOf(brandName) >= 0;
    }
}

Should lead to something like

[Nest] 1736 - 2018-3-26 12:16:38 [ExceptionsHandler] Cannot read property ‘all’ of undefined TypeError: Cannot read property ‘all’ of undefined

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Reactions:9
  • Comments:45 (8 by maintainers)

github_iconTop GitHub Comments

31reactions
cojackcommented, Jun 7, 2018

Hi guys, I found a solution for that, you can check my repo: https://github.com/neoteric-eu/nestjs-auth (btw, yesterday I was making a tech-workshops for developers in Gdańsk about how to proper handle authorisation and authentication with nest 😄 ), so, yeah @kamilmysliwiec I spread the love for Nest.js around the world 😸

@yamid-ny the solution for that in particular is done in two steps, first one:

		this.app = await NestFactory.create(AppModule, {
			logger: new AppLogger('Nest')
		});
		useContainer(this.app, {fallbackOnErrors: true});

The {fallbackOnErrors: true} is required, because Nest throw Exception when DI doesn’t have required class.

Second thing:

import {ValidatorConstraint, ValidatorConstraintInterface} from 'class-validator';
import {UserService} from './user.service';
import {Injectable} from '@nestjs/common';

@ValidatorConstraint({ name: 'isUserAlreadyExist', async: true })
@Injectable()
export class IsUserAlreadyExist implements ValidatorConstraintInterface {
	constructor(protected readonly userService: UserService) {}

	async validate(text: string) {
		const user = await this.userService.findOne({
			email: text
		});
		return !user;
	}
}

IsUserAlreadyExist have to be Injetable and registered in nest module

Like so:

import {Module} from '@nestjs/common';
import { DatabaseModule } from '../database/database.module';
import { UserController } from './user.controller';
import { userProviders } from './user.providers';
import { UserService } from './user.service';
import {IsUserAlreadyExist} from './user.validator';

@Module({
	controllers: [UserController],
	providers: [...userProviders, IsUserAlreadyExist, UserService],
	imports: [DatabaseModule],
	exports: [UserService]
})
export class UserModule {
}

Then when I try to do POST /users twice with payload as follow:

{"name": "cojack", "email": "xcojack@gmail.com", "password": "qwer1234", "roles": ["user"]}

I have got following response:

{"statusCode":422,"error":"Unprocessable Entity","message":[{"property":"email","children":[],"constraints":{"isUserAlreadyExist":"User already exists"}}]}

Hell yeah!

@fmeynard @jmaicaaan @hershko765 @roeehershko - you also guys might be interested how to solve this problem.

Regards 😉

23reactions
evilive3000commented, Jun 12, 2018

@kamilmysliwiec

useContainer(app, { fallbackOnErrors: true });

and

useContainer(app.select(AppModule), { fallbackOnErrors: true });

behaves different. In first case I’ve got few errors spitted into the console like this

[Nest] 3442   - 2018-6-12 16:43:51   [ExceptionHandler] Nest cannot find given element (it does not exist in current context)

while container tries to get Validator and MetadataStorage classes. But finally code works correctly, and I got all injected services as expected;

In the second case there are no errors and everything works like a charm.

Can you explain why?

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to inject service to validator constraint interface in nestjs ...
class -validator requires you to use service containers if you want to inject dependencies into your custom validator constraint classes.
Read more >
Dependency Injection — FluentValidation documentation
Validators can be used with any dependency injection library, such as Microsoft.Extensions.DependencyInjection . To inject a validator for a specific model, ...
Read more >
Custom validation with database in NestJS
It allows class-validator to use NestJS dependency injection container. Then we can create a repository, which will query our database:.
Read more >
Implementing Validators in Spring using Dependency Injection.
Writing actual validator has 3 different steps. Step 1 : Implement ValidatorFunction interface and annotate class with @Named. @Named works same ...
Read more >
class-validator - npm Package Health Analysis - Snyk
All security vulnerabilities belong to production dependencies of direct and indirect packages. License: MIT. Security Policy: No.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Hashnode Post

No results found