[인프런][JPA2][섹션1] 1강, 2강 복습

mutexlocking·2022년 6월 29일
0
  1. 회원 등록 API를 설계시, Entity로 Request를 그대로 받던 V1에 비해, RequestDTO를 쓰는 V2의 이점
    (1) API 스펙이 변하지 않는다. (2) API 스펙이 변하더라도, 그에 따라 Entity가 변하지는 않는다.
    고로, RestAPI 설계시 Request 값을 받고 / Response 값을 넘겨줄 때는 , Entity를 직접 쓰지 말고 반드시 별도의 DTO를 사용해야 함
 /**
     * <회원등록 API V1>
     *
     * [등록 V1] : 요청 값을  Member Entity가 직접 직접 받는 버전
     * [문제점]
     * 1. 기존 Member의 name값은 필수필드가 아니였음. 근데 화면에서 이름이 필수라는 이유로 , Entity의 name 필드에 검증 어노테이션이 추가되었음
     * -> Presentation 계층을 위한 검증 로직이 Entity에 들어간다는 것 자체가 문제 -> 왜냐하면 Presentation 계층은 API별로 여러개가 있을텐데, Entity는 유일한 하나이니 , 여러 검증 로직이 중첩되고 + 결국 한방향 검증밖에 못함
     * 2. Entity 자체를 요청이나 응답시 받으면 , 이후에 Entity의 필드가 변경되었을 때 , 요청이나 응답으로 넘어오거나 넘어갈 값도 달라지게 됨.
     * -> 그러면 "API" 즉 "약속이 아니게 됨!" -> 즉 Entity가 변경되면 "API 스펙이 변한다" == "API라는 약속이 깨진다" (연동시 , 정말 정말 Critical한 문제가 됨**)
     * [해결책]
     * : 각 API 별로 별도의 스펙을 위한 DTO를 각각 사용하여 , 그 DTO로 Request를 받고 , DTO에 따른 Response를 보내면 -> API 스펙도 변하지 않고, Entity도 역시 변하지 않는다.
     *
     *
     * */

    @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;
        }
    }
/**
     * <회원등록 API V2>
     *
     * [V1과의 차이점]
     * : 이제 Request를 받을 때도, Entity로 직접 받지 않고 / RequestDto를 사용해서 요청을 받는다 (Response는 원래 DTO였고)
     *
     * [그에 따른 효과]
     * : 결국 DTO라는 프레젠테이션 계층과 / Entity가 완전히 분리되는 덕분에 -> Entity는 변하지 않으면서 + API 스펙도 변하지 않게 된다 (뭔소리냐면, Entity가 변해도 API 스펙이 변하지 x) (이제는 너무 당연한 말!)
     *
     * [결론]
     * : API 스펙을 유지시키기 위해 요청과 응답시 넘어오고 넘어가게 되는 값은 반드시 별도의 DTO로 받는다. (그래야 Entity가 API스펙에 의해 변하지 않게 됨. - JPA를 쓰면 두 말할 것도 없이 중요)
     * */


    @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{
        private String name;
    }
  1. 회원 수정 API 설계시, V2에서 주목할 점
  • RestAPI 에성 리소스의 식별은 Path Variable로 한다. -> so id를 Path Variable로 받아 Member 식별
  • JPA의 update는 dirty checking을 이용한다. -> 이를 Service 단에 적용 해놔야, Controller는 Service.update() 한방으로 수정됨.
  • 그런데 Service단의 update() 메소드 구현 시 ,, 응답을 넘겨야 할 까 or 넘기지 않아야 할까?
    -> 이땐 커맨드(등록/수정/삭제) 와 vs 쿼리 (조회) 를 분리하자! 는 원칙을 따라라
    -> 즉 DB에 접근하여 어떤 동작을 수행하는 각각의 모듈에서는, 한 모듈당 커맨드 or 쿼리 둘 중 하나의 operation만 수행하는것이 , 추후 유지보수에 유리하다! (김영한 선생님의 말씀)
```

/**
<회원 수정 API V2>>
*/
@PutMapping("/api/v2/members/{id}")
public UpdateMemberResponse updateMemberV2(@PathVariable Long id, @RequestBody @Valid UpdateMemberRequest request){

    //은근히 주의할 점이, update를 JPA로 하려면, dirty checking을 해야 함 -> 따라서 먼저 조회한 후, setter로 필드를 바꿔줘야 함 => 당연히 Service 에서 제공하는 update는 그렇게 구현되어 O - so 그냥 쓰면 됨
    memberService.update(id, request.getName());
    Member findMember = memberService.findOne(id);
    return new UpdateMemberResponse(findMember.getId(), findMember.getName());

}



@Data
static class UpdateMemberRequest{
    private String name;
}

@Data
@AllArgsConstructor
static class UpdateMemberResponse{
    private  Long id;
    private  String name;

}



profile
개발자가 되고자 try 하는중

0개의 댓글