nest-profiler-validator
Validator-agnostic validation collector for @eleven-labs/nest-profiler — captures class-validator, nestjs-zod, or any validator's violations in the Validator panel.
@eleven-labs/nest-profiler-validator
@eleven-labs/nest-profiler-validator captures every DTO validation result (valid or invalid) and displays it in a dedicated Validator panel, inspired by Symfony's Web Profiler validator tab.
It is validator-agnostic: instead of being tied to class-validator, it wraps any validation PipeTransform and normalizes failures through pluggable, duck-typed extractors. Built-in extractors cover class-validator, nestjs-zod, and a generic HttpException fallback.

Installation
pnpm add @eleven-labs/nest-profiler-validatorThen install the validator you use:
# class-validator (default)
pnpm add class-validator class-transformer
# …or nestjs-zod
pnpm add nestjs-zod zodclass-validator/class-transformer are not peer dependencies — they are only required when you rely on the default class-validator pipe.
Setup
ValidatorCollectorModule.forRoot() registers ProfilerValidationPipe as the global APP_PIPE. It wraps your validation pipe — do not also register a separate global ValidationPipe.
With class-validator (default)
When pipe is omitted, a class-validator ValidationPipe is built from validationPipeOptions:
import { ValidatorCollectorModule } from '@eleven-labs/nest-profiler-validator';
@Module({
imports: [
ProfilerModule.forRoot({ isGlobal: true }),
ValidatorCollectorModule.forRoot({
validationPipeOptions: {
whitelist: true, // remove extra properties
transform: true, // transform payload to DTO class
// any other ValidationPipe options
},
}),
],
})
export class AppModule {}With nestjs-zod
Pass your own pipe via pipe; class-validator is never loaded:
import { ValidatorCollectorModule } from '@eleven-labs/nest-profiler-validator';
import { ZodValidationPipe } from 'nestjs-zod';
@Module({
imports: [
ProfilerModule.forRoot({ isGlobal: true }),
ValidatorCollectorModule.forRoot({ pipe: new ZodValidationPipe() }),
],
})
export class AppModule {}A NestJS app uses a single global validation strategy, so use one validator at a time.
Options
| Option | Type | Description |
|---|---|---|
enabled | boolean | Default true. When false, no pipe is installed. |
pipe | PipeTransform | The validation pipe to wrap. Defaults to a class-validator pipe built from the option below. |
validationPipeOptions | ValidationPipeOptions | Forwarded to the default class-validator pipe when pipe is omitted. |
extractors | ValidationViolationExtractor[] | Override the extractor chain. Defaults to [classValidator, zod, generic]. |
Prerequisite: value import for DTO types
For reflect-metadata to emit the DTO class constructor as parameter metadata, use a value import (not import type) on the DTO in your controllers:
// ✓ value import — emits reflect-metadata
import { CreateProductDto } from './dto/create-product.dto';
// ✗ type-only import — metadata is erased, metatype shows as 'Function'
import type { CreateProductDto } from './dto/create-product.dto';What it captures
For each @Body(), @Query(), or @Param() parameter using a DTO class:
| Field | Description |
|---|---|
source | body, query, param, or custom |
dtoClass | DTO class name (e.g., CreateProductDto) |
status | valid or invalid |
violationCount | Total number of constraint violations |
violations | Per-property breakdown with constraint names and messages |
Each violation entry includes:
property— the property path that failed (nested properties use dot notation)value— the rejected value (when available)constraints— map of constraint name → message (e.g.,{ isNotEmpty: "name should not be empty" })
How it works
ProfilerValidationPipe implements PipeTransform and wraps an inner pipe:
- On
transform(), it delegates to the inner pipe. On success it records avalidentry. - On failure it runs the configured extractors over the thrown error, records an
invalidentry with the normalized violations, then re-throws the original exception.
Extractors are tried in order; the first to recognize the error wins:
- class-validator —
createClassValidatorPipe()attaches the rawValidationError[]to the thrown exception (under a private symbol) so the full property/constraint tree is recovered. - nestjs-zod / zod — reads
ZodError.issues(viagetZodError()or a bareZodError). - generic — any
HttpExceptionexposing amessagestring/array (the universal fallback).
Reading the active profile uses CLS, so capture is concurrent-safe across requests.
Custom extractors
To support another validator, implement ValidationViolationExtractor and pass it via extractors:
import type { ValidationViolationExtractor } from '@eleven-labs/nest-profiler-validator';
const myExtractor: ValidationViolationExtractor = {
extract({ error }) {
// return ViolationEntry[] if recognized, otherwise null to defer to the next extractor
return null;
},
};
ValidatorCollectorModule.forRoot({ pipe: myPipe, extractors: [myExtractor] });Toolbar badge
- All valid: number of validated DTOs (e.g.,
1) - With violations: total violation count (e.g.,
3 violations)
Part of the nest-profiler toolkit · Powered & maintained by Eleven Labs