Fullstack CourseLearn by building
Back to week 3

Topic

DTOs & validation

Definition

A Data Transfer Object (DTO) is a class whose class-validator decorators declare the accepted shape and constraints for data crossing an API boundary, enforced at runtime by Nest’s global ValidationPipe.

In simpler words

A DTO is the input checklist for an endpoint — decorators say what’s allowed, and the global pipe rejects anything that breaks the rules before your service runs.

Ground this in CreateTicketDto, UpdateTicketDto, and ListTicketsQueryDto, plus the global ValidationPipe options set in main.ts.

After this you can

  • Read a DTO’s decorators and predict a 400
  • Explain whitelist vs forbidNonWhitelisted
  • Add @Type when a query value needs to become a number

Declaring and enforcing the shape

Definition

The global ValidationPipe — configured with whitelist, forbidNonWhitelisted, and transform — validates every DTO-typed parameter, strips properties without validator decorators, rejects requests containing unknown properties, and converts primitive values to their declared types.

In simpler words

whitelist quietly drops extra fields; forbidNonWhitelisted turns those extra fields into a 400 instead of silently ignoring them; transform makes the DTO instance actually usable as typed data.

CreateTicketDto requires a non-empty, length-bound title and allows an optional description and status.

Every field a client may send needs a decorator — an undecorated field is invisible to whitelist and gets stripped even if the client sends it.

CreateTicketDto

export class CreateTicketDto {
  @IsString()
  @MinLength(1)
  @MaxLength(200)
  title!: string;

  @IsOptional()
  @IsString()
  @MaxLength(5000)
  description?: string;
}

A missing title, an empty string, or a 6000-character description all fail validation before TicketsService.create runs.

Query strings need transform, not just validation

Definition

Query parameters arrive as strings, so a numeric or boolean DTO field needs an explicit transform such as @Type(() => Number) alongside its validator so the validated value has the correct runtime type.

In simpler words

IsInt alone would reject "20" as a string; @Type(() => Number) converts it to a number first, and then IsInt checks the number.

ListTicketsQueryDto applies this to page and limit, with @Min/@Max bounds that double as basic abuse protection on limit.

status and q stay plain strings, validated with @IsEnum and @IsString respectively.

ListTicketsQueryDto (numbers)

@ApiPropertyOptional({ default: 20 })
@IsOptional()
@Type(() => Number)
@IsInt()
@Min(1)
@Max(100)
limit = 20;

Without @Type, "100" would still be a string when @IsInt runs, and validation would fail.

Keep in mind

  • Give every accepted field a validator decorator — whitelist strips the rest.
  • Transform query strings to their real type before validating them.
  • Prefer 400 with field-level messages over letting bad data reach a service.

Test

Check your understanding

At least 10 questions — mix of concept, syntax, practical, and logic. Score ≥ 80% (enforced by the API) to save progress.

Checking your session…

10 questions · concept 3 · syntax 2 · practical 3 · logic 2

Concept1. Which statement best defines DTOs & validation?
Syntax2. Which code-level choice matches DTOs & validation?
Practical3. A reviewer spots a bug related to DTOs & validation. What is the right fix?
Logic4. Which reasoning correctly explains DTOs & validation?
Concept5. Which boundary does correct use of DTOs & validation preserve?
Practical6. What is the safest next step when applying DTOs & validation?
Syntax7. Which implementation direction matches the rule for DTOs & validation?
Logic8. Which consequence follows from applying DTOs & validation correctly?
Concept9. Which claim about DTOs & validation is true in this Nest + Postgres monorepo?
Practical10. Which team practice best demonstrates DTOs & validation?