Búsqueda de sitios web

javascript - La mejor manera de mapear DTOs y entidades en un servidor node.js con Arquitectura Limpia


Estoy aprendiendo Arquitectura Limpia usando Typescript/node.js y me está costando encontrar la mejor manera de mapear DTOs (Objetos de Transferencia de Datos) y Entidades de Dominio.

Los DTO se utilizan para transferir datos entre la capa de presentación (servidor web) y la capa de aplicación (casos de uso).

Encontré muchos recursos en línea que aconsejan varios patrones de diseño para lograr esto en varios lenguajes:

  • Mapeadores (aunque no es un patrón de diseño)
  • Fábricas
  • Constructoras
  • ...

En su libro "Clean Architecture", Robert C. Martin habla sobre "adaptadores" pero no pude encontrar ningún ejemplo explícito de implementación.

¿Cuál sería la mejor y más precisa decisión de diseño para el desarrollo a largo plazo?

Código base

DTO de Usuario

interface IUserDTO {

    id: number;
    firstName: string;
    lastName: string;
    email: string;
    age: number;

}

Entidad de usuario

interface IUser {

    getId(): string;

    setFirstName(firstName: string): void;
    getFirstName(): string;

    setLastName(lastName: string): void;
    getLastName(): string;

    setEmail(email: string): void;
    getEmail(): string;

    setAge(age: number): void;
    getAge(): number;
    
}

class User implements IUser {

    private _id: string;
    private _firstName:string;
    private _lastName: string;
    private _email: string;
    private _age: number;

    getId(): string {
        return this._id;
    }
    
    setFirstName(firstName: string): void {
        this._firstName = firstName;
    }

    getFirstName(): string {
        return this._firstName;
    }

    setLastName(lastName: string): void {
        this._lastName = lastName;
    }

    getLastName(): string {
        return this._lastName;
    }
        
    setEmail(email: string): void {
        this._email = email;
    }
    
    getEmail(): string {
        return this._email;
    }

    setAge(age: number): void {
        this._age = age;
    }

    getAge(): number {
        return this._age;
    }

}

Propuesta: Implementación de un mapeador contra interfaces

Pero, aunque es comúnmente adoptado, ¿es un patrón de diseño aceptable?

class UserMapper implements IToDtoMappable<IUser, IUserDto> {

    toDto(entity: IUser): IUserDto {
        const dto: IUserDto = {
            id: entity.getId(),
            firstName: entity.getFirstName(),
            lastName: entity.getLastName(),
            email: entity.getEmail(),
            age: entity.getAge(),
        };
        return dto;
    }

}