-
JPA - API 기본Spring/JPA 2022. 3. 21. 19:31728x90반응형
API에서는 하나만 기억하면 된다. 파라미터를 받거나 전송할 때 Entity를 사용하지 않고 DTO를 사용해야하는 것을 명심하자.
DTO 사용 시 이점
- 엔티티 대신에 RequestBody와 ResponseBody에 각각 DTO를 매핑한다.
- 엔티티와 프레젠테이션(화면) 계층을 위한 로직을 분리할 수 있다.
- 엔티티와 API 스펙을 명확하게 분리할 수 있다.
- 엔티티가 변해도 API 스펙이 변하지 않는다.
- 실무에서는 엔티티를 API 스펙에 노출하면 안된다.
엔티티로 매핑시 문제점
- 엔티티에 프레젠테이션 계층을 위한 로직이 추가된다
- 엔티티에 API 검증을 위한 로직이 들어간다.(@NotEmpty 등)
- 실무에서는 회원 엔티티를 위한 API가 다양하게 만들어지는데, 한 엔티티에
각각의 API를 위한 모든 요청 요구사항을 담기는 어렵다. - 엔티티가 변경되면 API 스펙이 변한다.
등록 API
등록 DTO
@Data class CreateMemberResponse { private Long id; public CreateMemberResponse(Long id) { this.id = id; } } @Data class CreateMemberRequest { private String name; }
@PostMapping("/api/v2/members") public CreateMemberResponse saveMemberV2(@RequestBody @Valid CreateMemberRequest request) { Member member = new Member(request.getName(), null); Long id = memberService.join(member); return new CreateMemberResponse(id); }
/api/v1/members
요청
{"name" : "hello"}응답{"id": 3}
수정 API
- 수정 시 주의할 점은 변경 감지를 사용하여 데이터를 수정해야 한다.(merge 사용 금지)
- PUT과 PATCH, POST의 사용
- PUT : 전체 업데이트를 할 때 사용
- PATCH, POST : 부분 업데이트를 할 때 사용
수정 DTO
@Data class UpdateMemberRequest { private String name; } @Data @AllArgsConstructor class UpdateMemberResponse { private Long id; private String name; }
@PutMapping("/api/v2/members/{id}") public UpdateMemberResponse updateMemberV2(@PathVariable("id") Long id, @RequestBody @Valid UpdateMemberRequest request) { memberService.update(id, request.getName()); Member findMember = memberService.findMember(id); return new UpdateMemberResponse(findMember.getId(), findMember.getName()); }
/api/v1/members
요청
{"name" : "change hello"}응답{"id": 3,"name": "change hello"}
조회 API
- 조회 API 역시 DTO를 사용해야 한다.
조회 DTO
@Data class Result<T> { private T data; public Result(T data) { this.data = data; } } @Data class MemberDto { private String name; public MemberDto(String name) { this.name = name; } }
@GetMapping("/api/v4/members") public Result membersV4() { List<Member> findMembers = memberService.findMembers(); //엔티티 -> DTO 변환 List<MemberDto> collect = findMembers.stream() .map(m -> new MemberDto(m.getName())) .collect(Collectors.toList()); return new Result(collect); }
여기서 중요한점은 Result 클래스로 컬렉션을 감싸서 전달한다는 점이다. 그 이유는 컬렉션을 전송하게 되면 배열로 전송이 되는데 배열로 전송이되면 필드를 추가 할 수 없게 된다. 따라서 컬렉션을 전달할 때는 향후 개별 필드를 추가할 수 있도록 클래스로 감싸서 전달하는게 좋다.
/api/v4/members
요청
응답
{"data": [{"name": "user1"},{"name": "user2"},{"name": "change hello"}]}위 응답에서 보면 클래스로 감싸서 전달하였기 때문에 필드를 자유롭게 추가할 수 있다.
(컬렉션으로 전달된 data를 보면 배열로 전달된것을 볼 수 있다.)
728x90반응형'Spring > JPA' 카테고리의 다른 글
JPA - API 개발 고급(OneToMany 컬렉션 조회 최적화) (0) 2022.03.23 JPA - API 개발 고급(OneToOne, ManyToOne 지연 로딩과 조회 성능 최적화) (0) 2022.03.22 JPA - Entity 설계시 주의점 (0) 2022.03.16 JPA - 설계 순서 (0) 2022.03.16 JPA - JPQL 기본 문법 2 (0) 2022.03.11