NestJS Profiler
Powered & maintained by

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.

Validator panel — DTO validation results with per-property constraint violations

Installation

pnpm add @eleven-labs/nest-profiler-validator

Then install the validator you use:

# class-validator (default)
pnpm add class-validator class-transformer

# …or nestjs-zod
pnpm add nestjs-zod zod

class-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:

app.module.ts
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:

app.module.ts
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

OptionTypeDescription
enabledbooleanDefault true. When false, no pipe is installed.
pipePipeTransformThe validation pipe to wrap. Defaults to a class-validator pipe built from the option below.
validationPipeOptionsValidationPipeOptionsForwarded to the default class-validator pipe when pipe is omitted.
extractorsValidationViolationExtractor[]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:

products.controller.ts
// ✓ 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:

FieldDescription
sourcebody, query, param, or custom
dtoClassDTO class name (e.g., CreateProductDto)
statusvalid or invalid
violationCountTotal number of constraint violations
violationsPer-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:

  1. On transform(), it delegates to the inner pipe. On success it records a valid entry.
  2. On failure it runs the configured extractors over the thrown error, records an invalid entry with the normalized violations, then re-throws the original exception.

Extractors are tried in order; the first to recognize the error wins:

  • class-validatorcreateClassValidatorPipe() attaches the raw ValidationError[] to the thrown exception (under a private symbol) so the full property/constraint tree is recovered.
  • nestjs-zod / zod — reads ZodError.issues (via getZodError() or a bare ZodError).
  • generic — any HttpException exposing a message string/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

On this page