mcpField
C
class-validator

class-validator

github.com/claude-dev-suiteDevelopment4645 installsUpdated 2d ago
Repository

About class-validator

A class-validator reference skill for TypeScript backend developers. It covers decorator-based DTO validation, NestJS integration, and common configuration issues.

Key features

  1. 01String, number, and date validation
  2. 02Nested object and array validation
  3. 03NestJS ValidationPipe integration
  4. 04Basic custom validator example
  5. 05Decorator setup and troubleshooting

Use cases

  1. 01Validating API request DTOs
  2. 02Filtering unknown fields in NestJS
  3. 03Checking nested objects and arrays

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/claude-dev-suite/claude-dev-suite --skill class-validator

After installing, type/class-validatorin Claude Code to confirm it loaded.

Bundled filesadvanced.md

Details

From the project README

Class-validator - Quick Reference

Full Reference: See advanced.md for custom validators, cross-field validation, validation groups, error formatting, and class-transformer integration.

Deep Knowledge: Use mcp__documentation__fetch_docs with technology: class-validator for comprehensive documentation.

Setup

npm install class-validator class-transformer
// tsconfig.json
{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  }
}

Basic Usage

import {
  validate,
  IsString,
  IsEmail,
  IsInt,
  Min,
  Max,
  Length,
  IsOptional,
} from 'class-validator';
import { plainToInstance } from 'class-transformer';

class CreateUserDto {
  @IsString()
  @Length(2, 50)
  name: string;

  @IsEmail()
  email: string;

  @IsInt()
  @Min(18)
  @Max(120)
  age: number;

  @IsOptional()
  @IsString()
  bio?: string;
}

// Validate
async function validateUser(data: unknown) {
  const user = plainToInstance(CreateUserDto, data);
  const errors = await validate(user);

  if (errors.length > 0) {
    throw new Error(errors.map((e) => Object.values(e.constraints || {})).flat().join(', '));
  }

  return user;
}

Common Decorators

String Validators
import {
  IsString, IsNotEmpty, Length, MinLength, MaxLength,
  Matches, IsUUID, IsEmail, IsUrl, IsIP,
} from 'class-validator';

class StringValidationDto {
  @IsString()
  @IsNotEmpty()
  required: string;

  @Length(5, 20)
  username: string;

  @MinLength(8)
  @Matches(/^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$/, {
    message: 'Password must contain letters and numbers',
  })
  password: string;

  @IsEmail()
  email: string;

  @IsUrl({ require_protocol: true })
  website: string;

  @IsUUID('4')
  id: string;
}
Number Validators
import { IsNumber, IsInt, IsPositive, Min, Max, IsDivisibleBy } from 'class-validator';

class NumberValidationDto {
  @IsNumber()
  decimal: number;

  @IsInt()
  integer: number;

  @IsPositive()
  positive: number;

  @Min(0)
  @Max(100)
  percentage: number;
}
Date Validators
import { IsDate, MinDate, MaxDate, IsISO8601 } from 'class-validator';
import { Type } from 'class-transformer';

class DateValidationDto {
  @IsDate()
  @Type(() => Date)
  date: Date;

  @MinDate(new Date('2020-01-01'))
  @Type(() => Date)
  afterDate: Date;

  @IsISO8601()
  isoString: string;
}
Array Validators
import {
  IsArray, ArrayMinSize, ArrayMaxSize, ArrayUnique,
  ArrayNotEmpty, ValidateNested,
} from 'class-validator';
import { Type } from 'class-transformer';

class ItemDto {
  @IsString()
  name: string;
}

class ArrayValidationDto {
  @IsArray()
  @ArrayNotEmpty()
  @ArrayMinSize(1)
  @ArrayMaxSize(10)
  @IsString({ each: true })  // Validate each item
  tags: string[];

  @IsArray()
  @ValidateNested({ each: true })
  @Type(() => ItemDto)
  items: ItemDto[];
}
Nested Object Validation
import { IsObject, ValidateNested } from 'class-validator';
import { Type } from 'class-transformer';

class AddressDto {
  @IsString()
  street: string;

  @IsString()
  city: string;
}

class UserWithAddressDto {
  @IsString()
  name: string;

  @ValidateNested()
  @Type(() => AddressDto)
  address: AddressDto;
}
Other Validators
import {
  IsBoolean, IsEnum, IsIn, IsOptional,
  IsCreditCard, IsPhoneNumber,
} from 'class-validator';

enum UserRole {
  ADMIN = 'admin',
  USER = 'user',
  GUEST = 'guest',
}

class MixedValidationDto {
  @IsBoolean()
  active: boolean;

  @IsEnum(UserRole)
  role: UserRole;

  @IsIn(['draft', 'published', 'archived'])
  status: string;

  @IsOptional()
  @IsCreditCard()
  creditCard?: string;
}

NestJS Integration

// main.ts
import { ValidationPipe } from '@nestjs/common';

app.useGlobalPipes(
  new ValidationPipe({
    whitelist: true,           // Strip non-decorated properties
    forbidNonWhitelisted: true, // Throw on unknown properties
    transform: true,            // Auto-transform payloads to DTO instances
    transformOptions: {
      enableImplicitConversion: true,
    },
  })
);
// users.controller.ts
@Controller('users')
export class UsersController {
  @Post()
  create(@Body() createUserDto: CreateUserDto) {
    // createUserDto is already validated and transformed
    return this.usersService.create(createUserDto);
  }

  @Get()
  findAll(@Query() query: PaginationQueryDto) {
    // Query params also validated
    return this.usersService.findAll(query);
  }

  @Get(':id')
  findOne(@Param('id', ParseUUIDPipe) id: string) {
    return this.usersService.findOne(id);
  }
}
Partial DTOs (for updates)
import { PartialType, OmitType, PickType, IntersectionType } from '@nestjs/mapped-types';

// All fields optional
export class UpdateUserDto extends PartialType(CreateUserDto) {}

// Omit specific fields
export class CreateUserWithoutPasswordDto extends OmitType(CreateUserDto, ['password']) {}

// Pick specific fields
export class LoginDto extends PickType(CreateUserDto, ['email', 'password']) {}

// Combine DTOs
export class ExtendedUserDto extends IntersectionType(CreateUserDto, AdditionalFieldsDto) {}

Custom Validator (Basic)

import {
  registerDecorator,
  ValidationOptions,
  ValidatorConstraint,
  ValidatorConstraintInterface,
  ValidationArguments,
} from 'class-validator';

@ValidatorConstraint({ async: false })
export class IsStrongPasswordConstraint implements ValidatorConstraintInterface {
  validate(password: string, args: ValidationArguments) {
    const hasUppercase = /[A-Z]/.test(password);
    const hasLowercase = /[a-z]/.test(password);
    const hasNumber = /\d/.test(password);
    const minLength = password.length >= 8;

    return hasUppercase && hasLowercase && hasNumber && minLength;
  }

  defaultMessage(args: ValidationArguments) {
    return 'Password must contain uppercase, lowercase, and number';
  }
}

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

// Usage
class RegisterDto {
  @IsStrongPassword()
  password: string;
}

When NOT to Use This Skill

  • Client-side validation - Use Zod with React Hook Form
  • Non-NestJS backends - Zod is more framework-agnostic
  • Functional programming patterns - Decorators require classes
  • Simple validation - Zod has simpler API

Comparison: class-validator vs Zod

Featureclass-validatorZod
StyleDecoratorsFunctional
FrameworkNestJS standardFramework agnostic
Transformclass-transformerBuilt-in
Bundle sizeLargerSmaller
Type inferenceManualAutomatic

Anti-Patterns

Anti-PatternWhy It's BadCorrect Approach
Missing @Type() decoratorNested validation failsUse @Type() for nested objects
No whitelist in ValidationPipeAccepts unknown propertiesSet whitelist: true
Using any in DTOsBypasses validationUse proper types
Manual validation in controllerCode duplicationUse ValidationPipe globally
Missing experimentalDecoratorsDecorators don't workEnable in tsconfig.json
Not using class-transformerPlain objects not validatedUse plainToInstance()

Quick Troubleshooting

IssueCauseSolution
Decorators not workingtsconfig misconfiguredEnable experimentalDecorators: true
Nested validation failsMissing @Type()Add @Type(() => NestedClass)
Validation not runningValidationPipe not setAdd ValidationPipe globally in main.ts
Unknown properties acceptedNo whitelistSet whitelist: true in ValidationPipe
Transform not workingMissing transform optionSet transform: true in ValidationPipe
Async validators failWrong setupUse async: true in @ValidatorConstraint

Checklist

  • tsconfig with decorators enabled
  • class-transformer for nested/transform
  • Global ValidationPipe in NestJS
  • whitelist and forbidNonWhitelisted
  • Custom validators for specific logic
  • Error formatting for API responses

Reference

Deep Knowledge: Use mcp__documentation__fetch_docs with technology: class-validator

Comments

Markdown supported