如何转换数据库实体User
:
class User {
public firstName: string;
public lastName: string;
public phone?: string;
public email: string;
public status: EUserState;
public tokens: Token[];
public password: string;
}
进入 DTO 实体GetUserDTO
:
class GetUserDTO {
public id: number;
public firstName: string;
public lastName: string;
public phone?: string;
public email: string;
}
在打字稿中?我正在使用@nestjs
、class-validator
和class-transformer
包,但我没有找到任何方法来使用它们来实现这一点。
有人可能会说,拥有DTO毫无意义,但是我们在服务器和客户端之间共享DTO,以维护API结构。
有什么想法吗?
有几种方法可以实现您想要的
- 您可以使用
Domain
或DTO
中的static
函数手动从Domain
模型映射到DTOs
export class Domain {
...
static toDTO(domain: Domain) {
// mapping goes here
}
}
或
export class Dto {
...
static fromDomain(domain: Domain) {
// mapping goes here
}
}
- 您可以使用第三方库:
automapper-ts
、@wufe/mapper
、@nartc/automapper
(我的库(或morphism
class-transformer
也可以被视为映射器,但是,如果您想从一个模型映射到另一个模型,那么class-transformer
真的做不到。
我在很多项目中都使用以下方式:
共享文件夹(可以分离github存储库,monore lib,npm等(
// user-response.dto.ts
class UserResponseDto {
public readonly id: string;
// other dto fields...
// the simplest way is the same type as entity but the better one is to use own type (TUserData) instead
constructor(data: UserEntity) {
this.id = data.id;
}
}
后端:
// user.entity.ts
@Entity('users')
class UserEntity {
// your fields...
}
// users.controler.ts
// import { UserResponseDto } from '@shared';
@Controller('users')
class UsersController {
@Get()
public async getUsers(): Promise<UserResponseDto[]> {
const data = await this.service.getUsers();
return data.map(user => new UserResponseDto(user);
}
// Bonus: example of class-transform, class-validate
@Post()
@UsePipes(new ValidationPipe()) // you can use your own pipe, check: TransformPipe implements PipeTransform { ...implementation }
public async createUser(
@Body() dto: UserCreateDto,
): Promise<UserResponseDto> {}
}
前端取决于选择的方式,但概念是相同的:
// users.api.ts
// import { UserResponseDto } from '@shared';
usersApi = {
endpoints: {
getUsers: (): UserResponseDto[]
}
}
首先,通过使用类转换器的classToPlain将Entity更改为纯json
。然后,通过使用类转换器的普通到类将普通 json 更改为 DTO 像下面一样
public async getAll(): Promise<ItemDTO[]> {
return await this.repo.find()
.then(items => items.map(e=>plainToClass(ItemDTO, classToPlain(e), { excludeExtraneousValues: true })));
}
此外,让我们在 DTO 中使用 Exclude, Expose of class-transformer for for 客户端数据,以便客户端查看。
@Exclude()
export class ItemDTO implements Readonly<ItemDTO> {
@ApiProperty({ required: true })
@IsUUID()
@Expose()
id: string;
}
如果 DTO 来自数据库模型,则可以使用生成器工具从架构创建 DTO
。这个库是为从Prisma模式生成DTO和实体而制作的: https://github.com/robblovell/prisma-generator-nestjs/tree/main
它不会转换您的实体,但它可以为您工作
如果您不使用Prisma,也许还有其他一些库可以使用其他ORM,只是为了让您意识到这一点!