📦 D3 · DTO + class-validator + ValidationPipe

D3 · DTO + class-validator +: The DTO (Data Transfer Object) + `class-validator` + `ValidationPipe` trio is the **STRUCTURALLY EXACT** counterpart of Spring's Bean Validation: in

The DTO (Data Transfer Object) + `class-validator` + `ValidationPipe` trio is the **STRUCTURALLY EXACT** counterpart of Spring's Bean Validation: in Java, `@NotBlank`/`@Size` are glued to a class field and `@Valid` triggers them; in Nest, `@IsNotEmpty()`/`@Length()` are glued to a DTO class field and `ValidationPipe` triggers them. This is COMPLETELY different from Express's (C4) "define rules, READ the result by hand" model — here the framework, like Spring, does validation automatically FOR you. So why does Nest return to this automation unlike Express? Because Nest already made an "opinionated" choice (D1) — once it adopted a decorator-based structure, validation naturally settles into the same decorator logic. But there is a NEW trap here: `ValidationPipe` is NOT "always on" like in Spring — it must be EXPLICITLY enabled in `main.ts` with `app.useGlobalPipes(new ValidationPipe())`. The DTO's decorators can remain decoration only, much like the missing `starter-validation` in B1 — except this time the root cause is not "missing library" but "library installed, just never ACTIVATED".

Writing the DTO and Activating the Pipe

Micro Lab: Code practice

Replace the TODO line with the critical line from the expected solution. This is not a real runtime; the goal is to reinforce writing the correct structure in a controlled way.

Step by Step: Code practice

Identify goal and input

Complete the critical line

Check output or behavior

Read the error message as evidence

Order the code reading and verification flow.

**🐞 Defect Birth — if `app.useGlobalPipes(new ValidationPipe())` is forgotten** **Code:** `CreateBugDto` was written FLAWLESSLY with all `class-validator` decorators, the controller uses the CORRECT type with `@Body() dto: CreateBugDto` — but `main.ts` has no `app.useGlobalPipes(new ValidationPipe())` line. **What happens:** Nest treats the DTO as just a TypeScript TYPE (compile-time information, gone once compiled to JavaScript); nobody RUNS the `class-validator` decorators. A `POST /api/v1/bugs { "title": "" }` request returns 201 instead of 400. **Why sneaky:** opening the DTO file, the decorators look entirely correct — a code review says "validation exists" and moves on. But for the decorators to ACTUALLY run, a global pipe must be activated; this is a third root cause, DIFFERENT from B1's missing dependency and C4's unread result: "the rules exist, but are never TRIGGERED". **Where the tester catches it:** sending a POST with an empty title and getting 201 — reviewing the DTO file is not enough, the presence of the `useGlobalPipes` call in `main.ts` must be separately verified.

🎬 The Pipe Hall of Nest

CreateBugDto decorators

Pipe unregistered → passes silently