ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • #실전2 - 4 회원조회 API
    SPRING-BOOT 2021. 3. 8. 11:41

    [출처] 인프런 김영한 강사님 -실전! 스프링 부트와 JPA 활용2 - 웹 애플리케이션 개발

    ddl-auto를 none으로 변경

    table drop 없이 데이터 넣어놓으면 계속 사용가능. 조회 테스트를 위해서 변경

     

     

     

    v1

    문제점 : Entity를 반환했다. 회원의 정보만 알고싶은데 orders 정보까지 노출이 된다.

    @JsonIgnore를 통해서 파싱할때 orders 정보를 뺄수 있다. 하지만 다른 API를 만들때 문제가 된다.

    그때마다 CASE를 바꿀 수 없는 노릇이다.

    그리고 ENTITY에 화면을 뿌리기 위한 프레젠테이션 로직이 추가되 버린 것이다.

    이렇게되면  ENTITY로 의존관계가 들어와야하는데 여기서는 ENTITY에서 의존관계가 나가는 것이다.

     

    회원조회 V1: 응답 값으로 엔티티를 직접 외부에 노출

    package jpabook.jpashop.api;
    
    @RestController
    @RequiredArgsConstructor
    public class MemberApiController {
           private final MemberService memberService;
           /**
           * 조회 V1: 응답 값으로 엔티티를 직접 외부에 노출한다.
           * 문제점
           * - 엔티티에 프레젠테이션 계층을 위한 로직이 추가된다.
           * - 기본적으로 엔티티의 모든 값이 노출된다.
           * - 응답 스펙을 맞추기 위해 로직이 추가된다. (@JsonIgnore, 별도의 뷰 로직 등등)
           * - 실무에서는 같은 엔티티에 대해 API가 용도에 따라 다양하게 만들어지는데, 한 엔티티에 각각의
          API를 위한 프레젠테이션 응답 로직을 담기는 어렵다.
           * - 엔티티가 변경되면 API 스펙이 변한다.
           * - 추가로 컬렉션을 직접 반환하면 항후 API 스펙을 변경하기 어렵다.(별도의 Result 클래스
          생성으로 해결)
           * 결론
           * - API 응답 스펙에 맞추어 별도의 DTO를 반환한다.
           */
           //조회 V1: 안 좋은 버전, 모든 엔티티가 노출, @JsonIgnore -> 이건 정말 최악, api가 이거
          하나인가! 화면에 종속적이지 마라!
           @GetMapping("/api/v1/members")
               public List<Member> membersV1() {
               return memberService.findMembers();
           }
    }

    조회 V1: 응답 값으로 엔티티를 직접 외부에 노출한

    문제점

        · 엔티티에 프레젠테이션 계층을 위한 로직이 추가된다.

        · 기본적으로 엔티티의 모든 값이 노출된다.

        · 응답 스펙을 맞추기 위해 로직이 추가된다. (@JsonIgnore, 별도의 뷰 로직 등등)

        · 실무에서는 같은 엔티티에 대해 API가 용도에 따라 다양하게 만들어지는데,

          한 엔티티에 각각의 API를 위한 프레젠테이션 응답 로직을 담기는 어렵다.

        · 엔티티가 변경되면 API 스펙이 변한다.

        · 추가로 컬렉션을 직접 반환하면 항후 API 스펙을 변경하기 어렵다.(별도의 Result 클래스 생성으로 해결)

    결론

        · API 응답 스펙에 맞추어 별도의 DTO를 반환한다.

     

    참고: 엔티티를 외부에 노출하지 마세요!

    실무에서는 member 엔티티의 데이터가 필요한 API가 계속 증가하게 된다. 어떤 API는 name 필드가 필요하지만, 어떤 API는 name 필드가 필요없을 수 있다.

    결론적으로 엔티티 대신에 API 스펙에 맞는 별도의 DTO를 노출해야 한다.

     

     

    하나의 JSON 스팩의 ARRAY안에는 똑같은 규칙의 JSON이 들어가야한다.

    entity를 외부에 노출해버리면 바로 Object로 감싸게 되고 위와같은 결과로 json이 도출된다.

    이렇게되면 DataList이외에 추가 값을 얻고싶을때 얻을 수가 없다.

     

     

    회원조회 V2: 응답 값으로 엔티티가 아닌 별도의 DTO 사용

        @GetMapping("/api/v2/members")
        public Result membersV2() {
            List<Member> findMembers = memberService.findMembers();
            //엔티티 -> DTO 변환
            List<MemberDto> collect = findMembers.stream()
                    .map(m -> new MemberDto(m.getName()))
                    .collect(Collectors.toList());
            return new Result(collect);
        }
    
        @Data
        @AllArgsConstructor
        static class Result<T> { 
        //Result라는 껍데기를 씌우고 data Filed의 값은 list가 될것이다
        //이런식으로 감싸줘야한다. 리스트를 바로 컬렉션으로내면 
        //JSON 배열타입으로 바로 나타내기때문에 유연성이 떨어진다.
            private T data;
        }
    
        @Data
        @AllArgsConstructor
        static class MemberDto{
            private String name;
        }

    · 엔티티를 DTO로 변환해서 반환한다.

    · 엔티티가 변해도 API 스펙이 변경되지 않는다.

    · 추가로 Result 클래스로 컬렉션을 감싸서 향후 필요한 필드를 추가할 수 있다.

    Result로 한번 감싸서 반환하기때문에 유연성이 생김

     

    만약 스팩을 count까지 뽑고 싶은 경우에도 

     

    도출된 결과와 같이 스팩이 바뀔수 있음.

    하지만 array가 첫시작이면스팩을 확장할 수 없고 유연성이 떨어진다.

     

     

    회원 조회시 Entity를 외부에 직접 반환하지말고 꼭  DTO로 변환해서 반환하자

     

    댓글

Designed by Tistory.