Serialización y deserialización

Intermedio
Nest
Nest
Actualizado: 15/06/2025

Cómo funciona la serialización en Nest

La serialización en NestJS es el proceso mediante el cual los objetos JavaScript se transforman en un formato que puede ser transmitido a través de la red, típicamente JSON. Este mecanismo es fundamental para controlar qué datos se envían al cliente y cómo se estructuran las respuestas de la API.

NestJS implementa la serialización a través de interceptores que se ejecutan automáticamente antes de enviar la respuesta al cliente. El framework utiliza la librería class-transformer para realizar estas transformaciones, permitiendo un control granular sobre el proceso de serialización.

Interceptor de serialización automática

Por defecto, NestJS aplica serialización automática a todas las respuestas de los controladores. Cuando un método de controlador retorna un objeto, el framework lo convierte automáticamente a JSON:

@Controller('users')
export class UsersController {
  @Get()
  findAll(): User[] {
    // Este array se serializa automáticamente a JSON
    return [
      { id: 1, name: 'Juan', email: 'juan@email.com', password: 'secret123' },
      { id: 2, name: 'María', email: 'maria@email.com', password: 'secret456' }
    ];
  }
}

El problema con este enfoque es que todos los campos del objeto se incluyen en la respuesta, incluyendo información sensible como contraseñas.

Control de campos con decoradores

Para controlar qué campos se incluyen en la serialización, NestJS utiliza decoradores de class-transformer. El decorador @Exclude() permite omitir campos específicos:

import { Exclude } from 'class-transformer';

export class User {
  id: number;
  name: string;
  email: string;
  
  @Exclude()
  password: string;
  
  @Exclude()
  createdAt: Date;
}

También puedes usar @Expose() para incluir únicamente los campos marcados, excluyendo todos los demás por defecto:

import { Expose } from 'class-transformer';

export class UserResponseDto {
  @Expose()
  id: number;
  
  @Expose()
  name: string;
  
  @Expose()
  email: string;
  
  // password y otros campos se excluyen automáticamente
}

Transformación de datos durante la serialización

La serialización también permite transformar los datos antes de enviarlos. Puedes modificar valores, cambiar nombres de propiedades o crear campos calculados:

import { Transform, Expose } from 'class-transformer';

export class User {
  @Expose()
  id: number;
  
  @Expose()
  @Transform(({ value }) => value.toUpperCase())
  name: string;
  
  @Expose()
  email: string;
  
  @Expose()
  @Transform(({ obj }) => `${obj.name} <${obj.email}>`)
  displayName: string;
  
  @Exclude()
  password: string;
}

Serialización condicional

Puedes aplicar serialización condicional basada en diferentes criterios como roles de usuario o contexto de la petición:

import { Expose, Transform } from 'class-transformer';

export class User {
  @Expose()
  id: number;
  
  @Expose()
  name: string;
  
  @Expose()
  email: string;
  
  @Expose({ groups: ['admin'] })
  password: string;
  
  @Expose({ groups: ['admin', 'owner'] })
  createdAt: Date;
}

Para usar grupos en el controlador, especifica el grupo en las opciones de serialización:

@Controller('users')
export class UsersController {
  @Get()
  @SerializeOptions({ groups: ['admin'] })
  findAll(): User[] {
    return this.usersService.findAll();
  }
}

Anidación y relaciones

La serialización maneja automáticamente objetos anidados y relaciones entre entidades. Puedes controlar cómo se serializan las relaciones:

import { Expose, Type } from 'class-transformer';

export class Post {
  @Expose()
  id: number;
  
  @Expose()
  title: string;
  
  @Expose()
  @Type(() => User)
  author: User;
  
  @Expose()
  @Type(() => Comment)
  comments: Comment[];
}

export class Comment {
  @Expose()
  id: number;
  
  @Expose()
  content: string;
  
  @Exclude()
  authorId: number;
}

Configuración global de serialización

Puedes configurar el comportamiento de serialización a nivel global en el archivo principal de la aplicación:

import { ClassSerializerInterceptor } from '@nestjs/common';
import { Reflector } from '@nestjs/core';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  
  // Configuración global del interceptor de serialización
  app.useGlobalInterceptors(
    new ClassSerializerInterceptor(app.get(Reflector), {
      strategy: 'excludeAll', // Excluir todo por defecto
      excludeExtraneousValues: true, // Excluir valores no definidos
      enableImplicitConversion: true // Conversión automática de tipos
    })
  );
  
  await app.listen(3000);
}

Esta configuración asegura que la serialización se aplique consistentemente en toda la aplicación, proporcionando un control uniforme sobre las respuestas de la API y mejorando la seguridad al evitar la exposición accidental de datos sensibles.

Fuentes y referencias

Documentación oficial y recursos externos para profundizar en Nest

Documentación oficial de Nest
Alan Sastre - Autor del tutorial

Alan Sastre

Ingeniero de Software y formador, CEO en CertiDevs

Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, Nest es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.

Más tutoriales de Nest

Explora más contenido relacionado con Nest y continúa aprendiendo con nuestros tutoriales gratuitos.

Aprendizajes de esta lección

  • Comprender el concepto de serialización en NestJS y su importancia.
  • Aprender a utilizar interceptores para la serialización automática de respuestas.
  • Controlar qué campos se incluyen o excluyen en la serialización mediante decoradores.
  • Aplicar transformaciones y serialización condicional según contexto o roles.
  • Configurar la serialización globalmente y manejar objetos anidados y relaciones entre entidades.