1. DTO란 무엇인가

DTO는 Data Transfer Object의 약자입니다. 말 그대로 데이터를 전달하는 용도의 객체입니다. 계층 사이에서 데이터를 옮기는 그릇이라고 생각하면 됩니다.

[클라이언트]  ←→  [Controller]  ←→  [Service]  ←→  [Repository]  ←→  [DB]
              DTO              DTO/Entity         Entity

클라이언트와 Controller 사이에서는 DTO가 오가고, Repository와 DB 사이에서는 Entity가 오갑니다.


2. 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 응답으로 반환하면 어떤 문제가 생기는지 하나씩 보겠습니다.

문제 1: 민감 정보 노출

// ❌ 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 변환의 책임까지 떠안는 것이라 좋지 않습니다.

문제 2: API 스펙이 DB 구조에 종속

DB 테이블에 컬럼을 추가하거나 이름을 바꾸면, API 응답 구조도 같이 바뀝니다. React에서 쓰던 필드 이름이 갑자기 바뀌면 프론트엔드가 깨집니다.

// DB 컬럼명 변경: author → writer
// Entity 수정하면 API 응답도 바뀜
private String writer;    // 기존: "author" → 변경: "writer"
// React에서 response.data.author가 갑자기 undefined!

DTO를 쓰면 Entity가 바뀌어도 DTO에서 매핑만 조정하면 됩니다. API 스펙은 유지됩니다.

문제 3: 순환 참조

Post가 Comment 목록을 가지고, Comment가 Post를 참조하면:

Post → comments → Comment → post → Post → comments → ...  무한 반복!