음식 주문 애플리케이션을 사용하면 음식점의 메뉴를 확인할 수 있습니다.
평소에 이러한 메뉴 API는 어떻게 제공 되고 있을까 궁금했습니다.
이번 프로젝트를 기회로 시중에 있는 배달 앱을 분석해보면서 API를 구현해보도록 하겠습니다.
스프링 부트와 JPA를 기본적으로 사용하며 스프링 데이터 JPA와 Qerydsl을 부분적으로 사용합니다.
언어는 java 8입니다.
가장 쉽게 접할 수 있는 배달의 민족앱을 기준으로 분석을 해보겠습니다. (제가 좋아하는 피자샵 매장을 예시로 들겠습니다.)
먼저 앱 내에서 음식점을 클릭하면 메뉴 리스트를 볼 수 있습니다.
정리 해보면 다음과 같습니다.
추가로 세부사항을 더 분석하겠습니다.
먼저 메뉴 API 사용 대상을 생각해보도록 하겠습니다.
첫번째로 음식점 관리 애플리케이션 입니다.
음식점 관리 앱에서는 음식점 사장님이 직접 메뉴를 등록, 수정, 삭제, 조회할 수 있어야 합니다.
두번쨰로는 음식 주문 애플리케이션 입니다.
음식 주문 앱에서는 음식점의 메뉴 조회가 주가 됩니다.
음식점의 전체 메뉴를 조회하고 메뉴를 클릭했을때 보여줄 메뉴 상세 정보를 조회할 수 있어야합니다.
정리 해보면 다음과 같습니다.
.png)
다의 도메인들을 일의 생명 주기에 종속적이라고 정의했습니다. (위 그림처럼 하나의 도메인이 다른 도메인을 혼자서 소유하는 경우 생명주기를 동일하게 가져가도 괜찮습니다. 하지만 나중에 주문과도 연계할 것을 생각하면 섣부른 결정 같아 보이지만 이번 프로젝트는 이렇게 설계 해보도록 하겠습니다.)메뉴 기본 옵션을 메뉴 옵션으로 통합해서 구성할까 생각했지만 서버와 클라이언트에서 불필요하게 신경 써야 될 로직이 증가하기 때문에 분리했습니다.@PostMapping("/api/v1/store/{storeId}/menu-group")
public void saveMenuGroup(@PathVariable("storeId") Long storeId, @RequestBody MenuGroupSaveDto menuGroupSaveDto) {
menuService.saveMenuGroup(storeId, menuGroupSaveDto);
}
@Transactional
public void saveMenuGroup(Long storeId, MenuGroupSaveDto menuGroupSaveDto) {
Store store = storeRepository.findById(storeId)
.orElseThrow(EntityNotFoundException::new);
menuGroupRepository.save(menuGroupSaveDto.toEntity(store));
}
@Getter
public class MenuGroupSaveDto {
private String name;
private Integer priority;
public MenuGroup toEntity(final Store store) {
MenuGroup menuGroup = MenuGroup.builder()
.name(name)
.priority(priority)
.store(store)
.build();
return menuGroup;
}
}
저장을 연쇄적으로 할 수 있게 구현해보니 이번에는 수정을 연쇄적으로 할 수 없을까 란 생각이 들었습니다.
저장과 수정을 통합해서 제공할 수 있다면, 클라이언트에서 좀 더 편하게 개발을 할 수 있지 않을까 생각합니다.
영속성 전이기능을 사용하면 부모 엔티티가 영속 상태로 변할때 자식 엔티티도 같이 영속 상태로 변합니다.
이를 이용해 저장 API 구현시 dto에 하위 엔티티 정보를 입력했을때 같이 저장되게 하면 어떻게 될까 생각했고 구현해보기로 했습니다.
@Getter
public class MenuGroupSaveDto {
private String name;
private Integer priority;
private List<MenuSaveDto> menuSaveList;
public MenuGroup toEntity(final Store store) {
MenuGroup menuGroup = MenuGroup.builder()
.name(name)
.priority(priority)
.store(store)
.build();
if (menuSaveList != null && menuSaveList.size() > 0) {
menuSaveList.forEach(msd -> msd.toEntity(menuGroup));
}
return menuGroup;
}
}