1. 문제 정의 — 왜 Node에서는 MapStruct가 안 보일까?
Java/Spring 환경에서는 MapStruct 같은 도구로
Entity ↔ DTO 매핑을 컴파일 타임에 자동 생성할 수 있다.
하지만 Node.js/TypeScript에서는 비슷한 경험을 기대하기 어렵다.
그 이유는 명확하다.
- TypeScript는 런타임에 타입 정보가 사라진다
- Annotation Processing 같은 컴파일 타임 코드 생성 구조가 없다
- 결국 “자동 매핑”을 위한 기반 자체가 부족하다
즉, 같은 문제를 다른 방식으로 풀어야 한다.
2. 접근 방식 전환 — “자동 매핑”이 아니라 “자동 생성”
Node/TS에서의 핵심 전략은 이것이다.
도구로 자동화하지 말고, 생성 프로세스를 자동화하라
즉,
- MapStruct 같은 라이브러리를 찾는 대신
- AI(Claude, GPT)를 활용해 DTO와 mapper를 생성한다
3. 실무 표준 구조
다음 구조를 기준으로 잡으면 유지보수성과 확장성이 모두 확보된다.
/domain → Entity
/dto → zod 기반 DTO
/mapper → 변환 함수 (AI 생성)
/controller → API Layer
4. DTO는 zod로 통합한다
TypeScript에서 DTO는 단순 타입이 아니다.
검증 + 타입 + 계약을 동시에 가져가야 한다.
이 역할을 Zod 하나로 해결할 수 있다.
import { z } from "zod";
export const UserDtoSchema = z.object({
id: z.number(),
name: z.string(),
});
export type UserDto = z.infer<typeof UserDtoSchema>;
장점
- 타입 + validation + runtime schema 통합
- 프론트/백엔드 공유 가능
- API contract 명확화
5. Mapper는 단순 함수로 유지한다
Node에서는 “마법 같은 자동 매핑”보다
명시적이고 단순한 함수가 더 강력하다
export const toUserDto = (entity: User): UserDto => ({
id: entity.id,
name: entity.name,
});
설계 원칙
- 비즈니스 로직 금지
- 1:1 매핑만 수행
- 테스트 가능하게 유지
- 사람이 작성하지 않고 AI로 생성
6. AI를 활용한 보일러플레이트 제거
이 구조의 핵심은 AI 활용이다.
다음과 같은 프롬프트를 사용하면 된다.
User 엔티티를 기반으로
zod DTO와 mapper 함수를 생성해줘.
조건:
- zod schema 사용
- z.infer로 타입 생성
- mapper는 순수 함수
- optional/null 안전 처리
- Date → ISO string 변환
- 중첩 객체는 별도 mapper로 분리
이렇게 하면 반복 작업은 사실상 0에 가깝게 줄어든다.
7. 실무에서 중요한 규칙
1) DTO 수동 작성 금지
→ 반드시 생성
2) mapper 수정 금지
→ 변경 시 재생성
3) 변환 규칙 고정
예:
- snake_case → camelCase
- Date → string
- null 처리 정책
이 규칙이 없으면 팀 전체가 무너진다.
8. MSA에서의 확장 전략
이 구조는 단일 서비스뿐 아니라 MSA에서도 그대로 확장된다.
특히 중요한 포인트:
- Response DTO
- Event DTO (Kafka 등)
👉 반드시 분리해야 한다
이걸 섞는 순간 서비스 간 결합도가 급격히 증가한다.
9. 결론
Node.js/TypeScript에서는
- MapStruct 같은 자동 매핑 도구를 찾는 것은 비효율적이다
- 대신
- zod로 DTO를 정의하고
- mapper 함수를 유지하며
- AI로 생성 자동화를 한다
이 구조가 가장 현실적이고 확장 가능하다.
한 줄 요약
Node에서는 “자동 매핑”이 아니라 “자동 생성 프로세스”를 설계해야 한다
LIST
'Software > Maker(Spring & Python & node)' 카테고리의 다른 글
| 테스트 격리란 무엇인가요? (0) | 2026.03.23 |
|---|---|
| Keycloak으로 구현하는 엔터프라이즈 인증·인가 아키텍처 (SSO, OAuth2, OIDC 완전 정리) (0) | 2026.03.19 |
| HTTP의 ETag에 대해서 설명해주세요. (0) | 2026.03.17 |
| 어떤 예외가 발생하면 트랜잭션을 롤백하나요? (0) | 2026.03.17 |
| 자바 개발자가 본 JS 변천사: var에서 TypeScript까지, 왜 우리는 TS로 가는가 (0) | 2026.03.16 |
