JPA
API + JPA
스파이더웹
2022. 9. 28. 10:33
728x90
반응형
회원 등록
@RestController
@RequiredArgsConstructor
public class MemberApiController {
private final MemberService memberService;
@PostMapping("/api/v1/members")
public CreateMemberResponse saveMemberV1(@RequestBody @Valid Member member){
}
@Data
static class CreateMemberResponse {
private Long id;
}
}
@RequestBody의 경우 Json 데이터의 내용을 Member 엔티티에 매핑 시켜준다
PostMan을 통해 post요청시 응답결과는 아래와 같다
현재 처럼 설계한 경우 엔티티 필드의 값을 변경하거나 혹은 이름을 넣지않아도 null로 값이 저장되는데, 이러한 부분을 방지하고자 Validation을 사용하는 경우 엔티티에서 유효성검사 등을 함께 실행하게된다. 이러한 경우 api를 위한 별도의 dto을 만들어 사용해야한다(예를들어 로그인에서도 간편로그인, OAuth를 이용 한 로그인 등 다양하게 달라질 수 있는데, api 별로 dto를 만들어 사용한다)
아래와 같이 개선하여 사용해야한다
@PostMapping("/api/v2/members")
public CreateMemberResponse saveMemberV2(@RequestBody @Valid CreateMemberRequest request){
Member member = new Member();
member.setName(request.name);
Long id = memberService.join(member);
return new CreateMemberResponse(id);
}
@Data
static class CreateMemberRequest {
private String name;
}
회원 수정
@PutMapping("/api/v2/members/{id}")
public UpdateMemberResponse updateMemberResponse(@PathVariable("id") Long id,
@RequestBody @Valid UpdateMemberRequest request){
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;
}
업데이트는 꼭 변경감지로 잊지말자!
회원 조회
@GetMapping("/api/v1/members")
public List<Member> memberV1(){
return memberService.findMembers();
}
문제점
- 엔티티에 프레젠테이션 계층을 위한 로직이 추가된다. 기
- 본적으로 엔티티의 모든 값이 노출된다.
- 응답 스펙을 맞추기 위해 로직이 추가된다. (@JsonIgnore, 별도의 뷰 로직 등등)
- 실무에서는 같은 엔티티에 대해 API가 용도에 따라 다양하게 만들어지는데, 한 엔티티에 각각의 API를 위한 프레젠테이션 응답 로직을 담기는 어렵다.
- 엔티티가 변경되면 API 스펙이 변한다. 추가로 컬렉션을 직접 반환하면 항후 API 스펙을 변경하기 어렵다.(별도의 Result 클래스 생성으로 해결)
아래와 같이 개선한다
@GetMapping("/api/v2/members")
public Result memberV2(){
List<Member> findMembers = memberService.findMembers();
List<MemberDto> collect = findMembers.stream()
.map(m -> new MemberDto(m.getName()))
.collect(Collectors.toList());
return new Result(collect);
}
@Data
@AllArgsConstructor
static class Result<T> {
private T data;
}
@Data
@AllArgsConstructor
static class MemberDto{
private String name;
}
728x90
반응형