Lew*_*ith 8 node.js typescript nestjs
只是想知道将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);
}
}
Run Code Online (Sandbox Code Playgroud)
我期待ClassSerializerInterceptor将照片对象序列化到DTO并返回如下内容:
{
id: 1,
name: 'Photo 1'
}
Run Code Online (Sandbox Code Playgroud)
但是我得到了一个包含所有属性的响应:
{
id = 1,
name = 'Photo 1',
description = 'Photo 1 description',
filename = 'file.png',
views = 10,
isPublished = true
}
Run Code Online (Sandbox Code Playgroud)
我基本上想要去除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});
}
Run Code Online (Sandbox Code Playgroud)
但是,如果我想要在响应中添加另一个属性,我必须做的不仅仅是将新属性添加到类中.我想知道是否有更好的"Nest方式".
因此,基于Jesse的精彩答案,我最终使用@Exclude()和@Expose()创建了DTO,以删除所有暴露的属性:
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;
}
Run Code Online (Sandbox Code Playgroud)
然后我创建了一个泛型变换拦截器,它调用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)));
}
}
Run Code Online (Sandbox Code Playgroud)
然后使用此拦截器将数据转换为任何类型:
@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;
}
Run Code Online (Sandbox Code Playgroud)
这给了我想要的东西:
{
id: 1,
name: 'Photo 1'
}
Run Code Online (Sandbox Code Playgroud)
绝对感觉更像鸟巢!我可以在任何需要的地方使用相同的拦截器,并改变我只需要更改DTO的响应.
快乐的时光.
一种可能的选择是使用@Exclude
和@Expose
装饰器标记DTO对象,然后使用以下命令进行转换plainToClass
:
@Exclude()
export class PhotoSnippetDto {
@Expose()
@IsNumber()
readonly id: number;
@Expose()
@IsString()
readonly name: string;
}
Run Code Online (Sandbox Code Playgroud)
假设你已按照上面的装饰,那么你可以这样做: const dto = plainToClass(PhotoSnippetDto, photo);
生成的对象采用您期望的形式,id
并name
显示在最终对象上.如果您稍后决定公开更多属性,只需将它们添加到DTO并用它们标记即可@Expose
.
此方法还允许您从正在使用的DTO中删除构造函数 Object.assign
归档时间: |
|
查看次数: |
2859 次 |
最近记录: |