Spring/API

API 개발 : 간단한 주문 조회 (지연 로딩)

JWonK 2022. 6. 26. 17:11
728x90
반응형

이번 게시글은 지난 게시글과는 달리 회원이 아닌 주문을 조회한다고 가정했을 경우이다.

조회이기 때문에 REST API : GET Method는 동일하다.

 

이번 간단한 주문 조회의 가정은 컬렉션 조회가 아닌 xToOne 관계 조회이다. 

주문과 연관 되어 있는 관계 들 중 xToOne으로 관계가 맺어져 있는 회원, 배송정보를 가져올 것이다.

 

  • 회원 조회가 아닌 주문 조회
  • REST API : GET Method 적용
  • 주문과 xToOne관계로 맺어져 있는 정보를 조회할 것
  • 즉, 컬렉션 조회가 아님
  • 주문과 연관되어있는 회원, 배송정보를 조회할 것
  • 지금까지 게시글로 원하는 API 반환을 위해서는 API 스펙에 맞춰 DTO 클래스를 설계하여 반환해야한다는 것을 알고 있다는 가정 하, DTO로 변환하여 반환하는 코드로 작성
  • 조건 : API 반환으로 원하는 조건은 { 주문 번호, 사용자 이름, 주문 날짜, 주문 상태, 배송지 정보} 이다. 이 스펙에 맞춰 DTO를 개발해야한다.

@RestController
@RequiredArgsConstructor
/**
 * Order
 * Order -> Member
 * Order -> Delivery
 * 즉, 컬렉션 조회가 아닌 xToOne(ManyToOne, OneToOne) 관계
 */
public class OrderSimpleApiController {

    private final OrderRepository orderRepository;
    
    @GetMapping("/api/v2/simple-orders")
    public List<SimpleOrderDto> ordersV2(){
        List<Order> orders = orderRepository.findAllByString(new OrderSearch());
        List<SimpleOrderDto> orderSDto = orders.stream()
                .map(o -> new SimpleOrderDto(o))
                .collect(Collectors.toList());

        return orderSDto;
    }

    @Data
    static class SimpleOrderDto{
        private Long orderId;
        private String name;
        private LocalDateTime orderDate;
        private OrderStatus orderStatus;
        private Address address;

        public SimpleOrderDto(Order order){
            orderId = order.getId();
            name = order.getMember().getUsername();
            orderDate = order.getOrderDate();
            orderStatus = order.getOrderStatus();
            address = order.getDelivery().getAddress();
        }
    }
}

우선 원하는 API 스펙에 맞춰 SimpleOrderDto 클래스를 설계하여 DTO를 생성해주었다. 우리는 DTO에 맞춰 반환해줄 것이다.

또한, 하나 생각해야할 것이 전 게시글에서 말했듯이 JSON 형태로 유연한 개발을 하기 위해서는 API를 반환해줄 때는 Result 클래스로 감싸주어 반환해주어야한다.

 

이렇게 개발하게 되면 잘 개발된 것 같다. 하지만 엔티티를 API에 노출하는 것과 위 코드와 동일한 문제점이 하나 발생한다.

 

바로 엔티티를 개발할 때 설정해두었던 LAZY설정으로 인해 값을 가져오기 위해서는 너무 많은 쿼리문을 호출해야한다.

이를 1 + N 문제라고 지칭한다. 예를 들어, 우리가 원하는 Order를 가져오고 Order와 연관되어 있는 회원, 배송정보를 가져오기 위해서 일단 Order를 모두 가져온다. 만약, Order가 3개 있다고 가정하면, Order 3개를 가져온 후, 각각의 Order와 연관되어 있는 회원, 배송정보를 위해 회원을 위한 쿼리문 3개 + 배송 정보를 위한 쿼리문 3개가 추가로 호출된다.

 

즉, 주문(1) + 회원(3) + 배송정보(3) = 7개의 쿼리문 호출이 된다. 만약 주문이 100개가 된다면? 매우 비효율적인 API 개발이 되어버린다.

 

(참고로 지연로딩은 영속성 컨텍스트에서 조회하므로, 이미 조회한 경우는 생략. 위 경우는 최악의 경우 고려)

 

따라서, DTO로 변환하는 것은 물론 추가로 최적화를 진행해야한다. 

 

다음 게시글로 최적화 과정을 업로드할 예정이다.

728x90
반응형