-
[Spring] API를 보낼 때 엔티티 리스트 통째로 보내면 안되는 이유Spring 2021. 11. 19. 16:09
@GetMapping("/api/v1/members") public List<Member> membersV1() { return memberService.findMembers(); }
다음은 엔티티를 리스트로 담아 리턴을 하는 경우다.
postman으로 결과값을 보면
[ { "id": 1, "name": "new-hello", "address": null, "orders": [] }, { "id": 2, "name": "member1", "address": { "city": "서울", "street": "test", "zipcode": "" }, "orders": [] }, { "id": 3, "name": "퉁그리", "address": { "city": "부산", "street": "ㅇㄹㅇ", "zipcode": "123" }, "orders": [] } ]
이런식으로 나오게 되는데 여기서 문제는 여러개 발생한다.
1. 엔티티에 프레젠테이션 계층을 위한 로직이 추가된다.
2. 기본적으로 엔티티의 모든 값이 노출된다.
3. 응답 스펙을 맞추기 위해 로직이 추가된다.(@JsonIgnore, 별도의 뷰 로직 등등)
4. 실무에서는 같은 엔티티에 대해 API가 용도에 따라 다양하게 만들어지는데, 한 엔티티에 각각의 API를 위한 프레젠테이션 응답 로직을 담기는 어렵다.
5. 엔티티가 변경되면 API 스펙이 변한다.
6. 추가로 컬렉션을 직접 반환하면 향후 API 스펙을 변경하기 어렵다.
이와 같은 문제들을 해결하기 위해서는 API 응답 스펙에 맞춰 별도의 DTO를 반환하고, 별도의 클래스를 생성하여 감싸서 api를 쏘는게 추후에 유지보수가 쉬워진다.
@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; }
멤버의 이름에 대해서만 api를 보내는 함수이다.
이렇게 api를 보내면 결과는 다음과 같다.
{ "data": [ { "name": "new-hello" }, { "name": "member1" }, { "name": "퉁그리" } ] }
이렇게 data라는 키값으로 담아져 오기때문에 추후에 api에 담을것이 더 필요하거나, 형식이 바뀌더라도 쉽게 바꿀 수 있다.
'Spring' 카테고리의 다른 글
[Spring] 컬렉션 조회 최적화 (0) 2021.11.25 [Spring] 쿼리 N+1 상황을 해결하는 방법 (0) 2021.11.23 [Spring] 변경 감지와 병합 (0) 2021.11.14 [Spring]test폴더에 yml파일을 따로 두면 좋은 이유 (0) 2021.11.10 [Spring] 양방향 연관관계 세팅시 필요한 연관관계 메소드 (0) 2021.11.09