npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@assemblerjs/dto

v1.0.1

Published

TypeScript decorators for Data Transfer Object (DTO) validation and transformation using `class-validator` and `class-transformer`.

Readme

@assemblerjs/dto

TypeScript decorators for Data Transfer Object (DTO) validation and transformation using class-validator and class-transformer.

Overview

@assemblerjs/dto provides a streamlined way to validate and transform DTOs in TypeScript applications. It leverages the power of class-validator and class-transformer to ensure data integrity and type safety.

Features

  • 🎯 Type-safe validation - Full TypeScript support
  • 🔄 Automatic transformation - Convert plain objects to class instances
  • Class-validator integration - Use all class-validator decorators
  • 🏭 Factory pattern - Create and validate DTOs easily
  • 🚨 Detailed errors - Custom error class with validation details
  • 🔁 Pre-call method decorators - Validate or adapt arguments before the method executes

Public API

All exports are re-exported from src/index.ts.

  • Dto() - marks a class as a DTO
  • createDto() - validate and transform a plain object into a DTO instance
  • createDtoSafe() - non-throwing DTO creation helper that returns structured issues
  • ValidateArg(index, DtoClass, options?) - validate and replace a method argument
  • ValidateBody(DtoClass, options?, index?) - resolve and validate the body argument
  • AdaptArg(index, SourceDto, TargetDto, mapper, options?) - validate, adapt, then validate again
  • AdaptBody(SourceDto, TargetDto, mapper, options?, index?) - body-oriented alias for AdaptArg
  • DtoValidationHooks - optional lifecycle hooks for validation (start/success/failure)
  • DtoDecoratorHooks - optional lifecycle hooks for decorator adaptation (start/success/failure)
  • DtoValidationError - validation error with a status code
  • DtoMetadataKeys - DTO metadata keys used by @Dto()
  • DtoSchemaExtractor - derive JSON schema from class-validator metadata

Validation Options (Normalized)

createDto supports a normalized options object:

await createDto(CreateUserDto, payload, {
  parseErrors: true,
  validation: {
    whitelist: true,
    forbidNonWhitelisted: true,
    groups: ['create'],
  },
});

Decorator helpers (ValidateArg, ValidateBody, AdaptArg, AdaptBody) internally use the same normalized flow with parseErrors: true.

You can plug optional hooks for observability:

await createDto(CreateUserDto, payload, {
  parseErrors: true,
  hooks: {
    onValidateStart: ({ dtoName }) => console.log('start', dtoName),
    onValidateSuccess: ({ dtoName }) => console.log('success', dtoName),
    onValidateFailure: ({ dtoName, issues }) => console.log('failure', dtoName, issues),
  },
});

Decorator-level adaptation hooks are also supported through decorator options:

@AdaptArg(0, ExternalDto, DomainDto, mapper, {
  hooks: {
    onAdaptStart: ({ methodName }) => console.log('adapt start', methodName),
    onAdaptSuccess: ({ methodName }) => console.log('adapt success', methodName),
    onAdaptFailure: ({ methodName, error }) => console.log('adapt failure', methodName, error),
  },
})

ValidationIssue Contract

createDtoSafe returns issues with a stable shape:

type ValidationIssue = {
  path: string;
  code: string;
  message: string;
  value?: unknown;
  context?: Record<string, unknown>;
};

context is populated from class-validator decorator context metadata when available.

Decorator Metadata Convention

@assemblerjs/dto uses the shared metadata key convention from @assemblerjs/common when resolving bodies for method decorators:

  • assemblerjs:param:body

This keeps DTO method decorators interoperable with @assemblerjs/fetch and @assemblerjs/rest.

Installation

npm install @assemblerjs/dto class-validator class-transformer reflect-metadata
# or
yarn add @assemblerjs/dto class-validator class-transformer reflect-metadata

Quick Start

import 'reflect-metadata';
import { Dto } from '@assemblerjs/dto';
import { IsString, IsEmail, IsInt, Min, Max } from 'class-validator';

@Dto()
class CreateUserDto {
  @IsString()
  name: string;

  @IsEmail()
  email: string;

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

// Valid data
const validDto = new CreateUserDto();
validDto.name = 'John Doe';
validDto.email = '[email protected]';
validDto.age = 30;

// Invalid data will throw DtoValidationError
const invalidDto = new CreateUserDto();
invalidDto.name = 'Jane';
invalidDto.email = 'not-an-email'; // Invalid email
invalidDto.age = 15; // Below minimum

API

@Dto() Decorator

Marks a class as a DTO and enables validation.

@Dto()
class MyDto {
  @IsString()
  field: string;
}

DTO Factory

Create and validate DTOs from plain objects:

import { createDto } from '@assemblerjs/dto';

const plainObject = {
  name: 'John',
  email: '[email protected]',
  age: 30
};

// Transform and validate
const dto = await createDto(CreateUserDto, plainObject);

Validation Errors

The package provides a custom error class with detailed validation information:

import { DtoValidationError } from '@assemblerjs/dto';

try {
  const dto = await createDto(CreateUserDto, invalidData);
} catch (error) {
  if (error instanceof DtoValidationError) {
    console.log(error.message);
    console.log(error.errors); // Array of validation errors
  }
}

Usage with class-validator

You can use all class-validator decorators:

import {
  IsString,
  IsEmail,
  IsInt,
  Min,
  Max,
  IsOptional,
  IsArray,
  ValidateNested,
  IsEnum
} from 'class-validator';
import { Type } from 'class-transformer';

enum Role {
  USER = 'user',
  ADMIN = 'admin'
}

@Dto()
class AddressDto {
  @IsString()
  street: string;

  @IsString()
  city: string;

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

@Dto()
class CreateUserDto {
  @IsString()
  name: string;

  @IsEmail()
  email: string;

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

  @IsEnum(Role)
  role: Role;

  @ValidateNested()
  @Type(() => AddressDto)
  address: AddressDto;

  @IsArray()
  @IsString({ each: true })
  @IsOptional()
  tags?: string[];
}

Usage with AssemblerJS

Integrate DTOs with AssemblerJS dependency injection:

import { Assemblage, AbstractAssemblage } from 'assemblerjs';
import { Dto } from '@assemblerjs/dto';

@Dto()
class UpdateUserDto {
  @IsString()
  @IsOptional()
  name?: string;

  @IsEmail()
  @IsOptional()
  email?: string;
}

@Assemblage()
class UserService implements AbstractAssemblage {
  async updateUser(id: string, data: UpdateUserDto) {
    // Data is already validated
    // Perform update logic
  }
}

Reflection API

Access DTO metadata at runtime:

import { getDtoMetadata } from '@assemblerjs/dto';

const metadata = getDtoMetadata(CreateUserDto);
// Use metadata for runtime introspection

OpenAPI Integration

@assemblerjs/dto works natively with @assemblerjs/openapi. Annotating a DTO class with @Dto() registers its class-validator metadata so that DtoSchemaExtractor can produce a JSON Schema at spec generation time.

import { Dto } from '@assemblerjs/dto';
import { IsString, IsInt, IsEmail, IsOptional } from 'class-validator';
import { Returns } from '@assemblerjs/openapi';

@Dto()
class UserDto {
  @IsInt() id!: number;
  @IsString() name!: string;
  @IsEmail() @IsOptional() email?: string;
}

// In a REST controller:
@Returns(200, UserDto, 'A single user')
@Get('/:id')
getOne(@Param('id') id: string) { ... }

The UserDto schema will be emitted under components/schemas/UserDto and referenced via $ref in the response object. See @assemblerjs/openapi for full details.

Requirements

  • Node.js: ≥ 18.12.0
  • TypeScript: ≥ 5.0
  • reflect-metadata: Required for decorators

TypeScript Configuration

Enable decorators in your tsconfig.json:

{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "target": "ES2020",
    "lib": ["ES2020"]
  }
}

For Contributors

Development

# Build the package
npx nx build dto

# Run tests
npx nx test dto

# Lint
npx nx lint dto

E2E coverage

The package includes a full end-to-end scenario under e2e/ that uses both @assemblerjs/rest and @assemblerjs/fetch.

  • Main scenario: e2e/dto-package.full-e2e.spec.ts
  • Fixtures: e2e/fixtures/
  • Generated logs: e2e/logs/dto-e2e.md

License

MIT


Part of the AssemblerJS monorepo