[스프링 JPA 2] API 개발

김하나·2023년 5월 24일

Spring Boot

목록 보기
14/16

실무에서는 엔티티를 API 스펙에 노출하면 안된다!

회원 등록 API - v1

//요청 값으로 Member 엔티티를 직접 받음
//= 엔티티를 RequestBody에 직접 매핑
@PostMapping("/api/v1/members")
    public CreateMemberResponse saveMemberV1(@RequestBody @Valid Member member){
        Long id = memberService.join(member);
        return new CreateMemberResponse(id);
    }

@Data
    static class CreateMemberResponse{
        private Long id;
        
        public CreateMemberResponse(Long id){
            this.id = id;
        }
   

→ Member entity에 제약 조건을 걸어두지 않았기 때문에 데이터를 입력하지 않고 send 해도 null로 데이터가 입력됨
따라서 Member entity에 @NotEmpty 제약 조건을 준다!
 

//...  
  @NotEmpty  //값이 없으면 안됨
  @Column(name = "name")
    private String name;

//...

@NotEmpty와 같은 제약을 주면 치명적 단점이 존재

  • 위의 name을 username 으로 (필드명을) 바꿀 시 api 스펙 자체가 바뀌기 때문에
    api가 동작하지 않는 오류 발생,
  • API에 따라 name이 필수인 경우도 있고 아닌 경우도 있을 수 있음

-> api 요청 스펙에 맞춰서 별도의 dto를 만들자!

 
엔티티를 RequestBody에 직접 매핑 하면 생기는 문제점

  1. 엔티티에 프레젠테이션 계층을 위한 로직이 추가된다.
  2. 엔티티에 Api 검증을 위한 로직(@NotEmpty 등)이 들어간다.
  3. 한 엔티티에 각각의 api를 위한 요구사항을 담기엔 어렵다.
  4. 엔티티가 변경되면 api 스펙이 변해버린다.

🍀 해결 방법

entity 대신 별도의 DTO를 만들어 파라미터로 받는다.

 

회원 등록 API - v2

//entity 대신 dto를 RequestBody에 매핑
@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);
    }

@Data
    static  class  CreateMemberRequest{
       @NotEmpty 
        private String name;
    }
  • member entity 대신 CreateMemberRequest라는 DTO를 RequestBody에 매핑했다.
  • 엔티티와 프레젠테이션 계층을 위한 로직을 분리할 수 있다.
  • 엔티티와 API 스펙을 명확하게 분리할 수 있다.
  • 엔티티가 변해도 API 스펙이 변하지 않는다.

0개의 댓글