이번 글은 데브코스 Spring Boot REST API 실습 9강 내용을 정리한 글이다.
9강에서는 기존에 사용하던 PostDto 클래스를 Java record로 변경하고,
DTO를 더 간결하고 명확하게 표현하는 방법을 다룬다.
또한 프론트엔드 개발자의 요구사항 변경을
엔티티가 아닌 DTO에서만 처리해야 하는 이유를 다시 한 번 확인한다.
9강에서 다룬 핵심은 다음 세 가지다.
class → record로 변경PostDto를 record로 변경
기존 PostDto는 일반 클래스 형태였다.
@Getter
public class PostDto {
private int id;
private LocalDateTime createdDate;
private LocalDateTime modifiedDate;
private String subject;
private String body;
}
9강에서는 이를 Java record로 변경한다.
public record PostDto(
int id,
LocalDateTime createdDate,
LocalDateTime modifiedDate,
String subject,
String body
) {
public PostDto(Post post) {
this(
post.getId(),
post.getCreateDate(),
post.getModifyDate(),
post.getTitle(),
post.getContent()
);
}
}
👉 DTO는 상태를 변경할 필요가 없기 때문에
record는 DTO에 매우 잘 어울리는 선택이다.
프론트 개발자 요구:
createdDate → createDate
subject → title
body → content
프론트엔드 개발자의 요청에 따라
API 응답 필드명이 변경되었다.
중요한 점은 엔티티는 전혀 수정하지 않았다는 것이다.
public record PostDto(
int id,
LocalDateTime createDate,
LocalDateTime modifyDate,
String title,
String content
) {
public PostDto(Post post) {
this(
post.getId(),
post.getCreateDate(),
post.getModifyDate(),
post.getTitle(),
post.getContent()
);
}
}
이 실습의 핵심 메시지는 명확하다.
프론트엔드와의 API 계약은 DTO에서만 관리한다.
엔티티는 내부 도메인 모델로 유지한다.
.map(post -> new PostDto(post)) → .map(PostDto::new)
기존 컨트롤러 코드는 다음과 같았다.
return items.stream()
.map(post -> new PostDto(post))
.toList();
이를 메서드 레퍼런스로 개선한다.
return items.stream()
.map(PostDto::new)
.toList();
9강은 단순한 문법 변경 강의가 아니다.
강의에서 반복해서 강조한 설계 관점은 다음과 같다.
9강은 DTO를 record로 개선하면서,
API 응답과 도메인 모델을 분리하는 설계를 완성하는 강의였다.
9강에서는 PostDto를 일반 클래스에서 record로 변경했다.
이는 단순한 문법 변경이 아니라, DTO의 역할을 더 명확히 표현하기 위한 선택이다.
record는 Java 16부터 도입된 문법으로,
데이터 전달만을 목적으로 하는 클래스(DTO)를 간결하게 표현하기 위해 만들어졌다.
Java 공식 정의를 한 문장으로 요약하면 다음과 같다.
record는 불변(immutable) 데이터 캐리어를 만들기 위한 클래스이다.
public record PostDto(
int id,
String title
) {
}
이 한 줄만 작성해도 Java는 다음을 자동으로 생성해준다.
id(), title())equals(), hashCode()toString()final (불변)record의 getter는 일반 클래스와 이름이 조금 다르다.
getId()id()하지만 Jackson은 두 형태를 모두 정상적인 getter로 인식한다.
따라서 record를 사용해도 JSON 직렬화에는 전혀 문제가 없다.
record도 생성자를 가질 수 있으며,
실무에서는 엔티티 → DTO 변환용 생성자를 자주 사용한다.
public record PostDto(
int id,
String title
) {
public PostDto(Post post) {
this(
post.getId(),
post.getTitle()
);
}
}
이 방식은
엔티티와 API 응답 객체를 분리하는 가장 깔끔한 패턴이다.
| 구분 | class + @Getter | record |
|---|---|---|
| 코드 길이 | 김 | 매우 짧음 |
| 불변성 | 직접 관리 | 기본 불변 |
| setter 존재 가능 | ⭕ | ❌ |
| equals/hashCode | Lombok 의존 | 기본 제공 |
| DTO 의도 표현 | 보통 | 매우 명확 |
DTO는 상태 변경이 필요 없는 객체이기 때문에
record가 구조적으로 더 잘 어울린다.
9강에서 record를 사용한 이유는 다음과 같다.
즉, record는
“이 클래스는 DTO다”라는 의도를 코드 자체로 표현해준다.
record는 만능이 아니다.
👉 이런 경우에는 일반 class가 더 적합하다.
record는 DTO의 목적(데이터 전달)을 가장 명확하게 드러내는 문법이며,
9강은 DTO 설계를 한 단계 더 깔끔하게 완성하는 강의였다.