Skip to content

Commit

Permalink
Reservation API 리팩터링 완료 (#176)
Browse files Browse the repository at this point in the history
* Refactor: Reservation QueryParameter 리팩토링 (#175)
  • Loading branch information
cxxxtxxyxx authored Oct 2, 2023
1 parent f6686e4 commit ff6c44a
Show file tree
Hide file tree
Showing 9 changed files with 89 additions and 15 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.livable.server.core.exception;

import lombok.AllArgsConstructor;
import lombok.Getter;
import org.springframework.http.HttpStatus;

@Getter
@AllArgsConstructor
public enum GlobalErrorCode implements ErrorCode {

INVALID_TYPE(HttpStatus.BAD_REQUEST, "입력 형식이 올바르지 않습니다");

private final HttpStatus httpStatus;
private final String message;
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public class GlobalExceptionHandler {

@ExceptionHandler(MethodArgumentTypeMismatchException.class)
public ResponseEntity<ApiResponse.Error> methodMethodArgumentTypeMismatchExceptionHandle(MethodArgumentTypeMismatchException e) {
return ApiResponse.error(e.getMessage(), HttpStatus.BAD_REQUEST);
return ApiResponse.error(GlobalErrorCode.INVALID_TYPE.getMessage(), HttpStatus.BAD_REQUEST);
}

@ExceptionHandler(BindException.class)
Expand All @@ -36,7 +36,7 @@ public ResponseEntity<ApiResponse.Error> globalRuntimeExceptionHandle(GlobalRunt
public ResponseEntity<ApiResponse.Error> runtimeExceptionHandle(RuntimeException e) {
log.error("runtimeExceptionHandle", e);

return ApiResponse.error(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
return ApiResponse.error(e.getCause().getCause().getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}

@ExceptionHandler(Exception.class)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.livable.server.core.util;

import com.livable.server.core.exception.GlobalErrorCode;
import com.livable.server.core.exception.GlobalRuntimeException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.convert.converter.Converter;

Expand All @@ -10,6 +12,10 @@ public class StringToLocalDateConverter implements Converter<String, LocalDate>

@Override
public LocalDate convert(String source) {
try {
return LocalDate.parse(source);
} catch (RuntimeException e) {
throw new GlobalRuntimeException(GlobalErrorCode.INVALID_TYPE);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
import com.livable.server.core.util.Actor;
import com.livable.server.core.util.JwtTokenProvider;
import com.livable.server.core.util.LoginActor;
import com.livable.server.reservation.domain.ReservationRequest;
import com.livable.server.reservation.dto.ReservationResponse;
import com.livable.server.reservation.service.ReservationService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDate;
import java.util.List;

@RequiredArgsConstructor
Expand All @@ -24,15 +24,14 @@ public class ReservationController {
@GetMapping("/places/{commonPlaceId}")
public ResponseEntity<ApiResponse.Success<Object>> findAvailableTimes(
@PathVariable Long commonPlaceId,
@RequestParam("startDate") LocalDate startDate,
@RequestParam("endDate") LocalDate endDate,
@ModelAttribute ReservationRequest.DateQuery dateQuery,
@LoginActor Actor actor
) {
) {

JwtTokenProvider.checkMemberToken(actor);

List<ReservationResponse.AvailableReservationTimePerDateDto> result =
reservationService.findAvailableReservationTimes(actor.getId(), commonPlaceId, startDate, endDate);
reservationService.findAvailableReservationTimes(actor.getId(), commonPlaceId, dateQuery);
return ApiResponse.success(result, HttpStatus.OK);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.livable.server.reservation.domain;

import com.livable.server.core.exception.ErrorCode;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.springframework.http.HttpStatus;

@Getter
@AllArgsConstructor
public enum ReservationErrorCode implements ErrorCode {

INVALID_DATE_RANGE(HttpStatus.BAD_REQUEST, "날짜 범위가 올바르지 않습니다");

private final HttpStatus httpStatus;
private final String message;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.livable.server.reservation.domain;

import com.livable.server.core.exception.GlobalRuntimeException;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.time.LocalDate;

@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class ReservationRequest {


@Getter
public static class DateQuery {

private final LocalDate startDate;
private final LocalDate endDate;

public DateQuery(LocalDate startDate, LocalDate endDate) {
validateRange(startDate, endDate);
this.startDate = startDate;
this.endDate = endDate;
}

private void validateRange(LocalDate startDate, LocalDate endDate) {
if (startDate.isAfter(endDate)) {
throw new GlobalRuntimeException(ReservationErrorCode.INVALID_DATE_RANGE);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.livable.server.invitation.repository.InvitationReservationMapRepository;
import com.livable.server.member.domain.MemberErrorCode;
import com.livable.server.member.repository.MemberRepository;
import com.livable.server.reservation.domain.ReservationRequest;
import com.livable.server.reservation.dto.AvailableReservationTimeProjection;
import com.livable.server.reservation.dto.AvailableReservationTimeProjections;
import com.livable.server.reservation.dto.ReservationResponse;
Expand All @@ -26,27 +27,26 @@ public class ReservationService {
public List<ReservationResponse.AvailableReservationTimePerDateDto> findAvailableReservationTimes(
Long memberId,
Long commonPlaceId,
LocalDate startDate,
LocalDate endDate
ReservationRequest.DateQuery dateQuery
) {


Member member = memberRepository.findById(memberId)
.orElseThrow(() -> new GlobalRuntimeException(MemberErrorCode.MEMBER_NOT_EXIST));

AvailableReservationTimeProjections availableReservationTimeProjections =
getAvailableReservationTimeProjections(member.getCompany().getId(), commonPlaceId, startDate, endDate);
getAvailableReservationTimeProjections(member.getCompany().getId(), commonPlaceId, dateQuery);

return availableReservationTimeProjections.toDto();
}

private AvailableReservationTimeProjections getAvailableReservationTimeProjections(
Long companyId, Long commonPlaceId, LocalDate startDate, LocalDate endDate
Long companyId, Long commonPlaceId, ReservationRequest.DateQuery dateQuery
) {
List<Long> usedReservationIds = invitationReservationMapRepository.findAllReservationId();
List<AvailableReservationTimeProjection> timeProjections =
reservationRepository.findNotUsedReservationTimeByUsedReservationIds(
companyId, commonPlaceId, startDate, endDate, usedReservationIds
companyId, commonPlaceId, dateQuery.getStartDate(), dateQuery.getEndDate(), usedReservationIds
);

return new AvailableReservationTimeProjections(timeProjections);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.livable.server.core.util.ActorType;
import com.livable.server.core.util.JwtTokenProvider;
import com.livable.server.core.util.TestConfig;
import com.livable.server.reservation.domain.ReservationRequest;
import com.livable.server.reservation.dto.ReservationResponse;
import com.livable.server.reservation.service.ReservationService;
import org.junit.jupiter.api.DisplayName;
Expand Down Expand Up @@ -57,8 +58,8 @@ void findAvailableTimesSuccessTest() throws Exception {
.build()
)
.collect(Collectors.toList());

given(reservationService.findAvailableReservationTimes(anyLong(), anyLong(), any(LocalDate.class), any(LocalDate.class)))
given(reservationService.findAvailableReservationTimes(anyLong(), anyLong(), any(ReservationRequest.DateQuery.class)))
.willReturn(result);

// when
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.livable.server.invitation.repository.InvitationReservationMapRepository;
import com.livable.server.member.domain.MemberErrorCode;
import com.livable.server.member.repository.MemberRepository;
import com.livable.server.reservation.domain.ReservationRequest;
import com.livable.server.reservation.dto.AvailableReservationTimeProjection;
import com.livable.server.reservation.dto.AvailableReservationTimeProjections;
import com.livable.server.reservation.dto.ReservationResponse;
Expand Down Expand Up @@ -70,6 +71,8 @@ void findAvailableReservationTimesSuccessTest() {

AvailableReservationTimeProjections projections = new AvailableReservationTimeProjections(queryResult);

ReservationRequest.DateQuery dateQuery = new ReservationRequest.DateQuery(LocalDate.now(), LocalDate.now().plusDays(1));

given(invitationReservationMapRepository.findAllReservationId()).willReturn(List.of(1L, 2L, 3L));
given(memberRepository.findById(anyLong())).willReturn(Optional.of(member));
given(reservationRepository.findNotUsedReservationTimeByUsedReservationIds(
Expand Down Expand Up @@ -97,10 +100,12 @@ void findAvailableReservationTimesFailTest() {
// given

given(memberRepository.findById(anyLong())).willReturn(Optional.empty());
ReservationRequest.DateQuery dateQuery =
new ReservationRequest.DateQuery(LocalDate.now(), LocalDate.now().plusDays(1));

// when
GlobalRuntimeException globalRuntimeException = assertThrows(GlobalRuntimeException.class, () ->
reservationService.findAvailableReservationTimes(1L, 1L, LocalDate.now(), LocalDate.now())
reservationService.findAvailableReservationTimes(1L, 1L, dateQuery)
);

// then
Expand Down

0 comments on commit ff6c44a

Please sign in to comment.