web-dev-qa-db-fra.com

Convertir l'entité en dto

Je me demande juste la meilleure façon de convertir un objet entité NestJS en DTO.

Disons que j'ai les éléments suivants:

import { IsString, IsNumber, IsBoolean } from 'class-validator';
import { Exclude } from 'class-transformer';

export class PhotoSnippetDto {
  @IsNumber()
  readonly id: number;

  @IsString()
  readonly name: string;

  constructor(props) {
    Object.assign(this, props);
  }
}

export class Photo {

  @IsNumber()
  id: number;

  @IsString()
  name: string;

  @IsString()
  description: string;

  @IsString()
  filename: string;

  @IsNumber()
  views: number;

  @IsBoolean()
  isPublished: boolean;

  @Exclude()
  @IsString()
  excludedPropery: string;

  constructor(props) {
    Object.assign(this, props);
  }
}

@Controller()
export class AppController {

  @Get()
  @UseInterceptors(ClassSerializerInterceptor)
  root(): PhotoSnippetDto {
    const photo = new Photo({
      id: 1,
      name: 'Photo 1',
      description: 'Photo 1 description',
      filename: 'photo.png',
      views: 10,
      isPublished: true,
      excludedPropery: 'Im excluded'
    });

    return new PhotoSnippetDto(photo);
  }

}

Je m'attendais à ce que ClassSerializerInterceptor sérialise l'objet photo au DTO et retourne quelque chose comme ceci:

{
  id: 1,
  name: 'Photo 1'
}

Mais je reçois toujours une réponse contenant toutes les propriétés:

{
  id = 1,
  name = 'Photo 1',
  description = 'Photo 1 description',
  filename = 'file.png',
  views = 10,
  isPublished = true
}

Je veux essentiellement supprimer toutes les propriétés qui ne sont pas définies dans le DTO.

Je sais que le ClassSerializerInterceptor fonctionne parfaitement lorsque vous utilisez @Exclude (), je m'attendais également à ce qu'il supprime également les propriétés non définies.

Je suis curieux de savoir la meilleure façon de procéder? Je sais que je pourrais faire quelque chose comme:

@Get('test')
@UseInterceptors(ClassSerializerInterceptor)
test(): PhotoSnippetDto {
  const photo = new Photo({
    id: 1,
    name: 'Photo 1',
    description: 'Photo 1 description',
    filename: 'photo.png',
    views: 10,
    isPublished: true,
    excludedPropery: 'Im excluded'
  });
  const { id, name } = photo;
  return new PhotoSnippetDto({id, name});
}

Mais si jamais je veux ajouter une autre propriété à la réponse, je devrais faire plus que simplement ajouter la nouvelle propriété à la classe. Je me demande s'il y a une meilleure "manière Nest" de le faire.

8
Lewsmith

Donc, sur la base de la réponse impressionnante de Jesse, j'ai fini par créer le DTO en utilisant @Exclude () et @Expose () pour supprimer toutes les propriétés sauf celles exposées:

import { IsString, IsEmail } from 'class-validator';
import { Exclude, Expose } from 'class-transformer';

@Exclude()
export class PhotoSnippetDto {
   @Expose()
   @IsNumber()
   readonly id: number;

   @Expose()
   @IsString()
   readonly name: string;
}

Et puis j'ai créé un intercepteur de transformation générique qui appelle plainToclass pour convertir l'objet:

import { Injectable, NestInterceptor, ExecutionContext } from '@nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { plainToClass } from 'class-transformer';

interface ClassType<T> {
    new(): T;
}

@Injectable()
export class TransformInterceptor<T> implements NestInterceptor<Partial<T>, T> {

    constructor(private readonly classType: ClassType<T>) {}

    intercept(context: ExecutionContext, call$: Observable<Partial<T>>, ): Observable<T> {
        return call$.pipe(map(data => plainToClass(this.classType, data)));
    }
}

Et puis utilisez cet intercepteur pour transformer les données en n'importe quel type:

@Get('test')
@UseInterceptors(new TransformInterceptor(PhotoSnippetDto))
test(): PhotoSnippetDto {
  const photo = new Photo({
    id: 1,
    name: 'Photo 1',
    description: 'Photo 1 description',
    filename: 'photo.png',
    views: 10,
    isPublished: true,
    excludedPropery: 'Im excluded'
  });
  return photo;
}

Ce qui me donne ce que je voulais:

{
  id: 1,
  name: 'Photo 1'
}

Se sent vraiment plus comme un nid! Je peux utiliser le même intercepteur partout où j'ai besoin et pour changer la réponse, je n'ai besoin que de changer les DTO.

Jours heureux.

9
Lewsmith