코딩과 결혼합니다

[JPA] API 설계 시 주의할 점(DTO 사용하기) 본문

2세/JPA

[JPA] API 설계 시 주의할 점(DTO 사용하기)

코딩러버 2024. 2. 17. 16:13
728x90

엔티티를 외부에 노출하거나 파라미터로 그대로 받는 것 ❌

@PostMapping("/api/v1/members")
public CreateMemberResponse saveMemberV1(@RequestBody @Valid Member member) {
    Long id = memberService.join(member);
    return new CreateMemberResponse(id);
}

엔티티를 파라미터로 받게 되면 딱 봤을 때 간단하긴 하다.

하지만 이대로 사용하면 문제가 생기는데

  1. API 스펙 문서를 까보지 않으면 엔티티에서 어느 값이 파라미터로 넘어오는지 모른다.
  2. 엔티티의 내용이 변경되면 ( 엔티티명 변경, 필드 추가 및 삭제 등) API 스펙 자체가 변경되는 문제가 발생할 수 있다.
  3. 필요로 하는 정보 외에도 엔티티에 있는 정보들이 모두 외부에 노출이 됨.
  4. 클라이언트의 다양한 API 스타일 요구에 대응할 수 없다.
@Entity
@Getter @Setter
public class Member {

    @Id
    @GeneratedValue
    @Column(name = "member_id")
    private Long id;

    @NotEmpty
    private String name;

    @Embedded
    private Address address;

    @OneToMany(mappedBy = "member")
    private List<Order> orders = new ArrayList<>();

}

 

이렇게 Entity에 name의 값을 필수로 받도록 설정을 해놓았는데, 어떤 API 스펙에서는 name을 null 값으로 받아도 되는 경우가 생길 수도 있다.

@PostMapping("/api/v2/members")
public CreateMemberResponse saveMemberV2(@RequestBody @Valid CreateMemberRequest request) {

    Member member = new Member();
    member.setName(request.getName());

    Long id = memberService.join(member);
    return new CreateMemberResponse(id);
}

v1 보다는 코드가 조금 더 복잡하나, Entity를 직접적으로 받지 않고 새로운 클래스를 만들어 파라미터로 받는다.

이럴 때에는 멤버 객체를 생성하고 setName을 해줄 때에, name의 필드명이 userName으로 바뀌었다고 해도 컴파일 오류를 통해 바로 잡을 수 있다. API는 전혀 영향을 받지 않는다.

@Data
static class CreateMemberRequest {
    @NotEmpty
    private String name;
}

 

다음으로 어느 값이 파라미터로 넘어오게 되는지를 명확히 알 수 있다.

여기에 validation을 추가해 주면 API 스펙마다 fit 하게 맞출 수 있어 유지보수할 때에도 큰 장점이 된다.