Привести сущность к dto - PullRequest
       4

Привести сущность к dto

0 голосов
/ 19 ноября 2018

Просто интересно, как лучше всего преобразовать объект сущности NestJS в DTO.

Допустим, у меня есть следующее:

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);
  }

}

Я ожидал, что ClassSerializerInterceptor сериализует объект фотографиив DTO и вернуть что-то вроде этого:

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

Но я получаю ответ, содержащий все свойства по-прежнему:

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

Я в основном хочу удалить все свойства, которые являютсяне определено в DTO.

Я знаю, что ClassSerializerInterceptor отлично работает при использовании @Exclude (), я просто ожидал, что он также удалит неопределенные свойства.

Мне любопытно, чтолучший способ пойти об этом?Я знаю, что могу сделать что-то вроде:

@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});
}

Но если я когда-нибудь захочу добавить другое свойство к ответу, мне придется сделать больше, чем просто добавить новое свойство в класс.интересно, есть ли лучший способ «гнезда» для этого.

Ответы [ 2 ]

0 голосов
/ 20 ноября 2018

Итак, основываясь на удивительном ответе Джесси, я в итоге создал DTO, используя @Exclude () и @Expose (), чтобы удалить все свойства, кроме открытых:

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;
}

И затем я создал общий перехватчик преобразования, которыйвызывает метод plainToclass для преобразования объекта:

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)));
    }
}

и затем использует этот перехватчик для преобразования данных в любой тип:

@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;
}

Что дает мне то, что я хотел:

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

Определенно чувствует себя как гнездо!Я могу использовать тот же перехватчик, где мне когда-либо нужно, и для изменения ответа, который мне когда-либо нужен, только для изменения DTO.

Счастливые дни.

0 голосов
/ 19 ноября 2018

Один из возможных вариантов - пометить объект DTO с помощью декораторов @Exclude и @Expose, а затем выполнить преобразование с помощью plainToClass:

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

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

Если вы украсили, как указано выше, вы можете сделать: const dto = plainToClass(PhotoSnippetDto, photo);

Полученный объект находится в ожидаемой вами форме, и только id и name отображаются на конечном объекте. Если позже вы решите выставить больше свойств, вы можете просто добавить их в свой DTO и пометить их @Expose.

Этот подход также позволяет вам удалить конструктор из вашего DTO, который использует Object.assign

...