Enterprise-backend-API's met NestJS · Les

Validatie van geneste en array-DTO's

Valideer geneste objecten en collecties met @ValidateNested, @Type en het verwijderen van niet-toegestane velden via whitelist.

Les 1 van 413 stappen

Validatie van geneste en array-DTO's is een gratis Enterprise-backend-API's met NestJS-les op CoddyKit. Dit is les 1 van 4. Je kunt de volledige les hieronder gratis lezen en daarna in de browser praktisch oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject Enterprise-backend-API's met NestJS. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus Enterprise-backend-API's met NestJS bevat in totaal 4 lessen.

Waarom geneste validatie hulp nodig heeft

NestJS koppelt class-validator aan class-transformer via de globale ValidationPipe. Voor vlakke DTO's werkt dit direct: decorateurs op elke eigenschap worden automatisch uitgevoerd.

Maar zodra een DTO een ander object of een array met objecten bevat, stopt de validatie stilzwijgend bij die grens. De validator ziet een onderliggende eigenschap, maar weet niet dat dit een klasse-instantie is waarvan de eigen decorateurs moeten worden uitgevoerd.

  • Een genest address-object wordt behandeld als een ondoorzichtige waarde.
  • Een items-array wordt gecontroleerd op het feit dat het een array is, maar de elementen worden nooit gevalideerd.

In deze les zie je hoe @ValidateNested, @Type en het verwijderen van eigenschappen via de whitelist deze hiaten dichten.

Het probleem in de code

Neem een orderpayload met een genest address-object. Alleen @ValidateNested toevoegen is niet voldoende — de validator heeft nog steeds een kind nodig dat een echte AddressDto-instantie is, geen gewoon object.

Zonder @Type laat class-transformer address als een gewoon object staan, waardoor @IsString() op city nooit wordt uitgevoerd. Ongeldige gegevens worden daardoor ongemerkt doorgelaten.

import { IsString, ValidateNested } from 'class-validator';

// AddressDto's own rules will NOT run yet
class AddressDto {
  @IsString()
  city: string;
}

export class CreateOrderDto {
  @ValidateNested() // declares intent, but lacks a target type
  address: AddressDto;
}

@Type maakt van het kind een echte instantie

Het ontbrekende onderdeel is @Type(() => AddressDto) uit class-transformer. Hiermee vertel je de transformer hoe de geneste waarde moet worden gemaakt, zodat het onbewerkte JSON-object wordt omgezet in een echte AddressDto-instantie.

Pas dan worden de decorateurs van het kind (@IsString, @IsNotEmpty, enzovoort) daadwerkelijk uitgevoerd. De vuistregel:

  • @ValidateNested() → "ga recursief verder in deze eigenschap".
  • @Type(() => Child) → "bouw deze eerst op als deze klasse".

Bijna altijd heb je beide samen nodig.

import { IsString, IsPostalCode, ValidateNested } from 'class-validator';
import { Type } from 'class-transformer';

class AddressDto {
  @IsString()
  city: string;

  @IsPostalCode('US')
  zip: string;
}

export class CreateOrderDto {
  @ValidateNested()
  @Type(() => AddressDto)
  address: AddressDto;
}

Transformatie inschakelen in de pipe

Om @Type effect te laten hebben, moet de ValidationPipe class-transformer uitvoeren. Schakel dit globaal in met transform: true.

Hiermee worden ook primitieve waarden omgezet: een tekenreeks van een routeparameter, zoals '42', wordt een number wanneer het DTO- of parametertype dat aangeeft. Zonder transform blijven geneste klassen gewone objecten en worden je @Type-aanwijzingen genegeerd.

import { ValidationPipe } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalPipes(
    new ValidationPipe({
      transform: true, // run class-transformer (required for @Type)
      whitelist: true,
      forbidNonWhitelisted: true,
    }),
  );
  await app.listen(3000);
}
bootstrap();

Arrays met DTO's valideren

Arrays met objecten hebben hetzelfde paar nodig, met één toevoeging: each: true. Hierdoor past @ValidateNested({ each: true }) de geneste validatie toe op elk element van de array.

@Type(() => ItemDto) zet elk onbewerkt element om in een ItemDto-instantie. Voeg @IsArray() en eventueel @ArrayMinSize(1) toe om ook de vorm van de verzameling zelf te bewaken.

import { IsArray, ArrayMinSize, IsString, IsInt, Min, ValidateNested } from 'class-validator';
import { Type } from 'class-transformer';

class OrderItemDto {
  @IsString()
  sku: string;

  @IsInt()
  @Min(1)
  quantity: number;
}

export class CreateOrderDto {
  @IsArray()
  @ArrayMinSize(1)
  @ValidateNested({ each: true }) // validate every element
  @Type(() => OrderItemDto)
  items: OrderItemDto[];
}

Diep geneste structuren

Dit patroon kan op elke diepte worden samengesteld. Een order heeft items en elk item heeft een eigen genest discount-object. Op elk niveau dat naar een andere klasse gaat, herhaal je het paar @ValidateNested + @Type.

Validatie werkt van boven naar beneden recursief: de order valideert zijn items-array, elk item valideert zijn discount-object en elke decorateur op een eindwaarde wordt uitgevoerd. Er is geen speciale vlag voor "diepe" validatie — je past gewoon dezelfde twee decorateurs toe bij elke grens.

import { ValidateNested, IsString, IsNumber, Max, Min } from 'class-validator';
import { Type } from 'class-transformer';

class DiscountDto {
  @IsNumber()
  @Min(0)
  @Max(1)
  rate: number;
}

class OrderItemDto {
  @IsString()
  sku: string;

  @ValidateNested()
  @Type(() => DiscountDto)
  discount: DiscountDto;
}

export class CreateOrderDto {
  @ValidateNested({ each: true })
  @Type(() => OrderItemDto)
  items: OrderItemDto[];
}

whitelist verwijdert onbekende eigenschappen

whitelist: true verwijdert elke eigenschap in de binnenkomende payload waarvoor geen validatiedecorateur op de DTO staat. Dit is een belangrijke beveiligingsmaatregel: clients kunnen geen extra velden zoals isAdmin of role je entiteiten binnensmokkelen.

Belangrijk is dat de whitelist recursief werkt op gevalideerde geneste objecten. Als een geneste AddressDto alleen city en zip declareert, wordt een geïnjecteerd country-veld in het geneste object ook verwijderd — maar alleen omdat @ValidateNested + @Type ervoor zorgen dat de validator erin afdaalt.

forbidNonWhitelisted: weigeren of verwijderen

Er zijn twee manieren om met onbekende velden om te gaan:

  • whitelist: true — verwijdert onbekende eigenschappen stilzwijgend en gaat verder.
  • whitelist + forbidNonWhitelisted: true — weigert het volledige verzoek met 400 en vermeldt de betreffende eigenschap.

Voor openbare API's is weigeren strenger en komen fouten van clients eerder aan het licht. Let op: forbidNonWhitelisted heeft alleen effect wanneer whitelist ook is ingeschakeld.

// Payload: { "city": "Austin", "zip": "73301", "hack": "x" }

// whitelist: true (only)
//   -> { city: 'Austin', zip: '73301' }  // 'hack' stripped

// whitelist: true + forbidNonWhitelisted: true
//   -> 400 Bad Request
//   -> message: ["property hack should not exist"]

Een puur class-validator-voorbeeld dat je kunt uitvoeren

Buiten NestJS werkt dezelfde engine rechtstreeks. Dit zelfstandige codefragment bouwt met plainToInstance een geneste instantie en valideert deze met validateSync — precies zoals de ValidationPipe intern doet.

Voer het uit om te zien hoe @ValidateNested + @Type een geneste fout zichtbaar maken.

import 'reflect-metadata';
import { IsString, IsInt, Min, ValidateNested, validateSync } from 'class-validator';
import { plainToInstance, Type } from 'class-transformer';

class ItemDto {
  @IsString() sku!: string;
  @IsInt() @Min(1) quantity!: number;
}

class OrderDto {
  @ValidateNested({ each: true })
  @Type(() => ItemDto)
  items!: ItemDto[];
}

const payload = { items: [{ sku: 'A1', quantity: 0 }] };
const dto = plainToInstance(OrderDto, payload);
const errors = validateSync(dto);

console.log(JSON.stringify(errors[0].children[0].children, null, 2));

Optionele en nullable geneste objecten

Een genest object dat mag ontbreken, moet worden gemarkeerd met @IsOptional(). Als het aanwezig is, wordt het nog steeds gevalideerd; als het ontbreekt, wordt het overgeslagen. Combineer dit zoals gebruikelijk met @ValidateNested en @Type.

Voor arrays zorgt @IsOptional() ervoor dat de volledige array mag ontbreken, terwijl @ArrayMinSize nog steeds een minimum afdwingt zodra de array wel is opgegeven. Behoud each: true, zodat aanwezige elementen gevalideerd blijven.

import { IsOptional, ValidateNested, IsString } from 'class-validator';
import { Type } from 'class-transformer';

class BillingDto {
  @IsString()
  taxId: string;
}

export class UpdateAccountDto {
  @IsOptional()
  @ValidateNested()
  @Type(() => BillingDto)
  billing?: BillingDto;
}

Veelvoorkomende valkuilen

Let op deze fouten; door alle vijf kan ongeldige data stilzwijgend worden doorgelaten:

  • @Type vergeten — het geneste object blijft een gewoon object; decorateurs van het kind worden nooit uitgevoerd.
  • transform: true vergeten — de pipe roept class-transformer nooit aan, waardoor @Type wordt genegeerd.
  • each: true vergeten bij arrays — alleen de eerste waarde of de volledige array wordt gecontroleerd, niet elk element.
  • Geen import van reflect-metadata — decorateurs leveren geen metadata; validatie doet niets.
  • whitelist uitschakelen — onbekende velden komen rechtstreeks in je servicelaag terecht.

Korte controle

Je hebt een array met geneste DTO's die je moet valideren. Welke combinatie is vereist?

Samenvatting

Je weet nu hoe je geneste DTO's en DTO-arrays in NestJS valideert:

  • @ValidateNested() vertelt de validator dat hij recursief moet afdalen in een kindobject; voeg { each: true } toe voor arrays.
  • @Type(() => Child) uit class-transformer zet onbewerkte JSON om in echte klasse-instanties, zodat de decorateurs van het kind worden uitgevoerd.
  • transform: true op de ValidationPipe is verplicht om @Type effect te laten hebben.
  • whitelist: true verwijdert niet-gedeclareerde eigenschappen recursief; forbidNonWhitelisted: true weigert ze in plaats daarvan met een 400.
  • Importeer altijd reflect-metadata en herhaal het paar @ValidateNested + @Type bij elke klassengrens, hoe diep die ook gaat.
Gratis beginnen

Leer TypeScript met een AI-tutor — gratis

Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.

Cursussen
20
Lessen
76

Veelgestelde vragen

Is de les “Validatie van geneste en array-DTO's” gratis?

Ja — de volledige tekst van “Validatie van geneste en array-DTO's” kun je hier gratis op het web lezen. Als je interactief wilt oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is, en de rest van de cursus Enterprise-backend-API's met NestJS wilt ontgrendelen, kun je upgraden naar CoddyKit PRO. De cursus Enterprise-backend-API's met NestJS bevat in totaal 4 lessen.

Wat leer ik in “Validatie van geneste en array-DTO's”?

Valideer geneste objecten en collecties met @ValidateNested, @Type en het verwijderen van niet-toegestane velden via whitelist. Je oefent met Enterprise-backend-API's met NestJS door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.

Heb ik ervaring nodig om met Enterprise-backend-API's met NestJS te beginnen?

Ervaring vooraf is niet nodig. Enterprise-backend-API's met NestJS op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 1 van 4.

Hoe lang duurt de les “Validatie van geneste en array-DTO's”?

De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.

Kan ik code schrijven en uitvoeren in deze les over Enterprise-backend-API's met NestJS?

Ja. Elke les over Enterprise-backend-API's met NestJS bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.

Alle lessen in deze cursus

  1. Validatie van geneste en array-DTO's
  2. Aangepaste validators en asynchrone constraints
  3. Responsvormgeving met ClassSerializerInterceptor
  4. Conditionele validatie en dynamische groepen
← Terug naar Enterprise-backend-API's met NestJS