Serialisering kontrollerar hur objekt transformeras till JSON som skickas i svar — helt avgörande är det utesluter känsliga fält (som lösenord) och formar utdata. NestJS hanterar detta med ClassSerializerInterceptor och class-transformer-dekoratörer.
Problemet: läckage av känslig data
// ❌ returning an entity directly leaks the password hash!
@Get(":id")
findOne(@Param("id") id: string) {
return this.usersService.findOne(id); // { id, name, email, password: "$2b$..." } 😱
}
Att returnera databasenheter direkt kan exponera fält som aldrig borde nå klienten (lösenordshashar, interna flaggor, tokens) — ett allvarligt säkerhets-/integritetsproblem.
Lösningen: @Exclude och ClassSerializerInterceptor
import { Exclude } from "class-transformer";
export class User {
id: number;
name: string;
email: string;
@Exclude() // this field is REMOVED from responses
password: string;
}
// enable the serializer interceptor (globally or per-controller)
@UseInterceptors(ClassSerializerInterceptor)
@Controller("users")
export class UsersController {
@Get(":id")
findOne(@Param("id") id): User {
return this.usersService.findOne(id); // password is automatically stripped
}
}
// or globally: app.useGlobalInterceptors(new ClassSerializerInterceptor(app.get(Reflector)))
ClassSerializerInterceptor tillämpar class-transformer-dekoratörer när responserna serialiseras, så @Exclude()-fält tas automatiskt bort — men bara om du returnerar klassinstanser (inte vanliga objekt).
Fler transformationsdekoratörer
export class User {
@Expose() id: number; // explicitly include (with excludeAll strategy)
@Exclude() password: string; // remove from output
@Expose({ name: "full_name" }) // rename in the output
name: string;
@Transform(({ value }) => value.toUpperCase()) // transform the value
code: string;
@Exclude({ toPlainOnly: true }) // exclude only when serializing OUT (not on input)
internalField: string;
}
Du måste returnera klassinstanser
// ⚠️ the interceptor only transforms CLASS INSTANCES — plain objects pass through unchanged
return new User(data); // ✅ decorators apply
return plainToInstance(User, data); // ✅ convert a plain object to an instance
return { ...data }; // ❌ plain object — @Exclude is IGNORED!
Ett vanligt misstag: serialiseringsdekoratörer fungerar bara på faktiska klassinstanser, så du måste returnera en instans (ORM-enheter är vanligtvis instanser; manuellt skapade vanliga objekt behöver konvertering).
Alternativ: dedikerade response-DTOer
Instead of decorating entities, map to a separate Response DTO containing only the
fields meant for the client — explicit, decoupled from the DB model, and very safe.
Varför det är viktigt
Att kontrollera responsserialiseringen är viktigt för både säkerhet och ren API-design.
Den mest kritiska anledningen är att förhindra läckage av känslig data — att returnera databasenheter direkt kan exponera lösenordshashar, interna fält, tokens eller annan data som aldrig får nå klienterna, en vanlig och allvarlig sårbarhet.
NestJS's ClassSerializerInterceptor tillsammans med class-transformer-dekoratörer (@Exclude, @Expose, @Transform) tillhandahåller ett rent, deklarativt sätt att forma responserna — automatiskt tar bort uteslutna fält, byter namn och transformerar värden.
Att förstå detta är väsentlig vardaglig kunskap för alla API:er som returnerar användar- eller domändata, och att känna till huvudfällan — att serialisering bara fungerar på klassinstanser, inte vanliga objekt (en ofta förekommande källa till "varför är lösenordet fortfarande synligt?"-buggar) — är praktiskt viktigt.
Lika värdefullt är att känna igen alternativmönstret med dedikerade response-DTOer (mappning av enheter till explicita outputklasser som endast innehåller klientsäkra fält), som frikopplar API-kontraktet från databasmodellen och är det säkraste tillvagagångssättet för känslig data.
Att korrekt kontrollera serialiseringen är ett kännetecken för säkra, väl utformade NestJS-API:er och ett ofta relevant problem i verkliga applikationer som hanterar någon icke-offentlig data.
