Bird
Raised Fist0
NestJSframework~20 mins

Custom validation decorators in NestJS - Practice Problems & Coding Challenges

Choose your learning style10 modes available
Challenge - 5 Problems
🎖️
Custom Validation Master
Get all challenges correct to earn this badge!
Test your skills under time pressure!
❓ component_behavior
intermediate
2:00remaining
What is the output when validating a DTO with this custom decorator?
Given this NestJS custom validation decorator and DTO, what will be the validation result if the input value is 'abc123'?
NestJS
import { registerDecorator, ValidationOptions, ValidatorConstraint, ValidatorConstraintInterface, ValidationArguments } from 'class-validator';

@ValidatorConstraint({ async: false })
export class IsAlphaOnlyConstraint implements ValidatorConstraintInterface {
  validate(text: string, args: ValidationArguments) {
    return /^[A-Za-z]+$/.test(text);
  }
  defaultMessage(args: ValidationArguments) {
    return 'Text ($value) must contain only letters';
  }
}

export function IsAlphaOnly(validationOptions?: ValidationOptions) {
  return function (object: Object, propertyName: string) {
    registerDecorator({
      target: object.constructor,
      propertyName: propertyName,
      options: validationOptions,
      constraints: [],
      validator: IsAlphaOnlyConstraint,
    });
  };
}

class SampleDto {
  @IsAlphaOnly({ message: 'Only letters allowed!' })
  name: string;
}

// Input: { name: 'abc123' }
AValidation throws a runtime error
BValidation passes successfully
CValidation fails with message: 'Text (abc123) must contain only letters'
DValidation fails with message: 'Only letters allowed!'
Attempts:
2 left
💡 Hint
Think about what the regex /^[A-Za-z]+$/ checks for and what input 'abc123' contains.
📝 Syntax
intermediate
2:00remaining
Which option correctly registers a custom validator in NestJS?
You want to create a custom validation decorator using class-validator in NestJS. Which of the following code snippets correctly registers the validator?
AregisterDecorator({ target: object.constructor, propertyName, validator: MyValidator, options: validationOptions });
BregisterDecorator({ target: object.constructor, propertyName, validator: new MyValidator(), options: validationOptions });
CregisterDecorator({ target: object.constructor, propertyName, validator: MyValidator });
DregisterDecorator({ target: object, propertyName, validator: MyValidator, options: validationOptions });
Attempts:
2 left
💡 Hint
Remember the target should be the constructor of the object, not the object instance itself.
🔧 Debug
advanced
2:00remaining
Why does this custom validator always pass validation?
Consider this custom validator code in NestJS. Why does it always pass validation regardless of input?
NestJS
import { ValidatorConstraint, ValidatorConstraintInterface } from 'class-validator';

@ValidatorConstraint({ async: false })
export class AlwaysTrueValidator implements ValidatorConstraintInterface {
  validate(value: any) {
    return true;
  }
  defaultMessage() {
    return 'This should never fail';
  }
}

// Used in a decorator but validation never fails
AThe validator class is not decorated with @Injectable().
BThe validate method always returns true, so validation never fails.
CThe defaultMessage method is not called.
DThe decorator is missing the registerDecorator call.
Attempts:
2 left
💡 Hint
Look at the return value of the validate method.
❓ state_output
advanced
2:00remaining
What is the validation error message for this input?
Given this custom validator and DTO, what error message will be shown if the input is { age: 17 }?
NestJS
import { registerDecorator, ValidationOptions, ValidatorConstraint, ValidatorConstraintInterface, ValidationArguments } from 'class-validator';

@ValidatorConstraint({ async: false })
export class IsAdultConstraint implements ValidatorConstraintInterface {
  validate(age: number, args: ValidationArguments) {
    return age >= 18;
  }
  defaultMessage(args: ValidationArguments) {
    return `Age must be at least 18, but got ${args.value}`;
  }
}

export function IsAdult(validationOptions?: ValidationOptions) {
  return function (object: Object, propertyName: string) {
    registerDecorator({
      target: object.constructor,
      propertyName: propertyName,
      options: validationOptions,
      constraints: [],
      validator: IsAdultConstraint,
    });
  };
}

class UserDto {
  @IsAdult({ message: 'User must be adult!' })
  age: number;
}

// Input: { age: 17 }
AValidation fails with message: 'User must be adult!'
BValidation passes successfully
CValidation fails with message: 'Age must be at least 18, but got 17'
DValidation throws a runtime error
Attempts:
2 left
💡 Hint
Check which message is prioritized when both defaultMessage and options.message exist.
🧠 Conceptual
expert
2:00remaining
Which statement about custom validation decorators in NestJS is TRUE?
Select the correct statement about creating and using custom validation decorators with class-validator in NestJS.
AThe defaultMessage method is required and must return a string synchronously.
BCustom validators must always be asynchronous and return a Promise<boolean>.
CThe validate method can be synchronous or asynchronous, but the decorator must specify async: true if asynchronous.
DCustom decorators cannot use constructor injection for dependencies.
Attempts:
2 left
💡 Hint
Think about how async validation is handled in class-validator.

Practice

(1/5)
1. What is the main purpose of creating a custom validation decorator in NestJS?
easy
A. To create new routes in the application
B. To automatically generate database schemas
C. To handle HTTP requests and responses
D. To define your own rules for validating data inputs

Solution

  1. Step 1: Understand validation decorators

    Validation decorators in NestJS are used to check if data meets certain rules before processing.
  2. Step 2: Purpose of custom validation decorators

    Custom validation decorators let you create your own specific rules that are not covered by built-in validators.
  3. Final Answer:

    To define your own rules for validating data inputs -> Option D
  4. Quick Check:

    Custom validation decorators = custom data rules [OK]
Hint: Custom decorators create your own data validation rules [OK]
Common Mistakes:
  • Confusing validation decorators with routing or database features
  • Thinking custom decorators generate schemas automatically
  • Assuming they handle HTTP requests directly
2. Which of the following is the correct way to start defining a custom validator class in NestJS?
easy
A. Use @Injectable decorator on the class
B. Use @Controller decorator on the class
C. Use @ValidatorConstraint decorator on the class
D. Use @Module decorator on the class

Solution

  1. Step 1: Identify the decorator for custom validators

    In NestJS, custom validation classes must be marked with @ValidatorConstraint to tell the system they are validators.
  2. Step 2: Differentiate from other decorators

    @Controller is for routing, @Injectable for services, and @Module for modules, not for validation.
  3. Final Answer:

    Use @ValidatorConstraint decorator on the class -> Option C
  4. Quick Check:

    @ValidatorConstraint marks custom validator classes [OK]
Hint: Custom validators use @ValidatorConstraint decorator [OK]
Common Mistakes:
  • Using @Controller or @Module instead of @ValidatorConstraint
  • Forgetting to decorate the validator class
  • Confusing service decorators with validation decorators
3. Given this custom validator code snippet, what will be the output when validating the value "abc123"?
import { ValidatorConstraint, ValidatorConstraintInterface } from 'class-validator';

@ValidatorConstraint({ name: 'isAlphaOnly', async: false })
export class IsAlphaOnly implements ValidatorConstraintInterface {
  validate(text: string) {
    return /^[A-Za-z]+$/.test(text);
  }
  defaultMessage() {
    return 'Text must contain only letters';
  }
}
medium
A. Validation fails because 'abc123' contains numbers
B. Validation passes because 'abc123' contains letters
C. Validation passes because regex allows numbers
D. Validation throws an error due to syntax

Solution

  1. Step 1: Analyze the regex in validate method

    The regex /^[A-Za-z]+$/ matches only strings with letters from start to end, no numbers allowed.
  2. Step 2: Check the test string 'abc123'

    This string contains numbers '123', so it does not match the regex and validate returns false.
  3. Final Answer:

    Validation fails because 'abc123' contains numbers -> Option A
  4. Quick Check:

    Regex /^[A-Za-z]+$/ rejects numbers [OK]
Hint: Check regex carefully to see what characters it allows [OK]
Common Mistakes:
  • Assuming partial matches pass validation
  • Ignoring numbers in the test string
  • Thinking regex allows digits when it does not
4. Identify the error in this custom validation decorator code:
import { registerDecorator, ValidationOptions, ValidatorConstraint, ValidatorConstraintInterface } from 'class-validator';

@ValidatorConstraint({ async: true })
export class IsEvenNumber implements ValidatorConstraintInterface {
  validate(value: number) {
    return value % 2 === 0;
  }
}

export function IsEven(validationOptions?: ValidationOptions) {
  return function (object: Object, propertyName: string) {
    registerDecorator({
      name: 'isEven',
      target: object.constructor,
      propertyName: propertyName,
      options: validationOptions,
      validator: IsEvenNumber,
    });
  };
}
medium
A. The validate method should return a Promise because async is true
B. The registerDecorator call is missing the validate method
C. The decorator function should not accept validationOptions
D. The class should not have @ValidatorConstraint decorator

Solution

  1. Step 1: Check async flag and validate method

    The @ValidatorConstraint decorator has async: true, so validate must return a Promise<boolean>.
  2. Step 2: Validate method returns boolean, not Promise

    Currently, validate returns a boolean directly, which conflicts with async: true.
  3. Final Answer:

    The validate method should return a Promise because async is true -> Option A
  4. Quick Check:

    async: true requires Promise return [OK]
Hint: If async: true, validate must return Promise<boolean> [OK]
Common Mistakes:
  • Returning boolean instead of Promise when async is true
  • Omitting @ValidatorConstraint decorator
  • Misusing registerDecorator parameters
5. You want to create a custom validation decorator that checks if a string property contains at least one uppercase letter and one digit. Which approach correctly combines the concepts to implement this in NestJS?
hard
A. Use built-in decorators @IsUppercase and @IsNumber together on the property
B. Create a class with @ValidatorConstraint, implement validate() using regex, then use registerDecorator in a function to apply it
C. Create a service with @Injectable and call it inside the DTO without decorators
D. Use only registerDecorator with a simple function without a class or @ValidatorConstraint

Solution

  1. Step 1: Understand custom validation structure

    Custom validators require a class decorated with @ValidatorConstraint implementing validate() method.
  2. Step 2: Use registerDecorator to link the class to a decorator function

    This function applies the validator to the property in the DTO.
  3. Step 3: Implement validate() with regex checking uppercase and digit presence

    This ensures the string meets both conditions in one check.
  4. Final Answer:

    Create a class with @ValidatorConstraint, implement validate() using regex, then use registerDecorator in a function to apply it -> Option B
  5. Quick Check:

    Custom validator class + registerDecorator function = correct approach [OK]
Hint: Combine @ValidatorConstraint class with registerDecorator function [OK]
Common Mistakes:
  • Skipping the validator class and using only registerDecorator
  • Trying to use services instead of decorators for validation
  • Assuming built-in decorators cover combined conditions
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard