DTO는 Data Transfer Object의 약자입니다. 말 그대로 데이터를 전달하는 용도의 객체입니다. 계층 사이에서 데이터를 옮기는 그릇이라고 생각하면 됩니다.
[클라이언트] ←→ [Controller] ←→ [Service] ←→ [Repository] ←→ [DB]
DTO DTO/Entity Entity
클라이언트와 Controller 사이에서는 DTO가 오가고, Repository와 DB 사이에서는 Entity가 오갑니다.
아직 JPA Entity를 안 배웠지만, 2단계에서 이런 Entity 클래스를 만들게 됩니다:
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Post {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private String content;
private String author;
private String password; // 게시글 비밀번호
@OneToMany(mappedBy = "post")
private List<Comment> comments; // 댓글 목록
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
이걸 그대로 API 응답으로 반환하면 어떤 문제가 생기는지 하나씩 보겠습니다.
// ❌ Entity를 그대로 반환
@GetMapping("/{id}")
public Post getPost(@PathVariable Long id) {
return postRepository.findById(id).orElseThrow();
}
// 응답에 password가 포함됨!
{
"id": 1,
"title": "제목",
"password": "1234",
"comments": [...]
}
비밀번호가 그대로 클라이언트에 전달됩니다. @JsonIgnore를 Entity에 붙여서 막을 수 있지만, 그건 Entity가 JSON 변환의 책임까지 떠안는 것이라 좋지 않습니다.
DB 테이블에 컬럼을 추가하거나 이름을 바꾸면, API 응답 구조도 같이 바뀝니다. React에서 쓰던 필드 이름이 갑자기 바뀌면 프론트엔드가 깨집니다.
// DB 컬럼명 변경: author → writer
// Entity 수정하면 API 응답도 바뀜
private String writer; // 기존: "author" → 변경: "writer"
// React에서 response.data.author가 갑자기 undefined!
DTO를 쓰면 Entity가 바뀌어도 DTO에서 매핑만 조정하면 됩니다. API 스펙은 유지됩니다.
Post가 Comment 목록을 가지고, Comment가 Post를 참조하면:
Post → comments → Comment → post → Post → comments → ... 무한 반복!