diff --git a/src/main/java/roomescape/reservation/docs/ReservationTimeAPI.kt b/src/main/java/roomescape/reservation/docs/ReservationTimeAPI.kt new file mode 100644 index 00000000..5ed33cea --- /dev/null +++ b/src/main/java/roomescape/reservation/docs/ReservationTimeAPI.kt @@ -0,0 +1,58 @@ +package roomescape.reservation.docs + +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.Schema +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.responses.ApiResponses +import io.swagger.v3.oas.annotations.tags.Tag +import jakarta.servlet.http.HttpServletResponse +import jakarta.validation.Valid +import jakarta.validation.constraints.NotNull +import org.springframework.http.HttpHeaders +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.* +import roomescape.auth.web.support.Admin +import roomescape.auth.web.support.LoginRequired +import roomescape.common.dto.response.CommonApiResponse +import roomescape.common.dto.response.RoomescapeApiResponse +import roomescape.common.dto.response.RoomescapeApiResponse.Companion.success +import roomescape.common.dto.response.RoomescapeErrorResponse +import roomescape.reservation.web.ReservationTimeInfosResponse +import roomescape.reservation.web.ReservationTimeRequest +import roomescape.reservation.web.ReservationTimeResponse +import roomescape.reservation.web.ReservationTimesResponse +import java.time.LocalDate + +@Tag(name = "4. 예약 시간 API", description = "예약 시간을 조회 / 추가 / 삭제할 때 사용합니다.") +interface ReservationTimeAPI { + + @Admin + @Operation(summary = "모든 시간 조회", tags = ["관리자 로그인이 필요한 API"]) + @ApiResponses(ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true)) + fun getAllTimes(): ResponseEntity> + + @Admin + @Operation(summary = "시간 추가", tags = ["관리자 로그인이 필요한 API"]) + @ApiResponses(ApiResponse(responseCode = "201", description = "성공", useReturnTypeSchema = true)) + fun saveTime( + @Valid @RequestBody reservationTimeRequest: ReservationTimeRequest, + ): ResponseEntity> + + @Admin + @Operation(summary = "시간 삭제", tags = ["관리자 로그인이 필요한 API"]) + @ApiResponses(ApiResponse(responseCode = "204", description = "성공", useReturnTypeSchema = true)) + fun removeTime( + @PathVariable id: Long + ): ResponseEntity> + + @LoginRequired + @Operation(summary = "예약 가능 여부를 포함한 모든 시간 조회", tags = ["로그인이 필요한 API"]) + @ApiResponses(ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true)) + fun findAllAvailableReservationTimes( + @RequestParam date: LocalDate, + @RequestParam themeId: Long + ): ResponseEntity> +} diff --git a/src/main/java/roomescape/reservation/web/ReservationTimeController.kt b/src/main/java/roomescape/reservation/web/ReservationTimeController.kt index 389a182e..5ccb18e3 100644 --- a/src/main/java/roomescape/reservation/web/ReservationTimeController.kt +++ b/src/main/java/roomescape/reservation/web/ReservationTimeController.kt @@ -1,108 +1,66 @@ -package roomescape.reservation.web; +package roomescape.reservation.web -import java.time.LocalDate; - -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseStatus; -import org.springframework.web.bind.annotation.RestController; - -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.media.Content; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.responses.ApiResponses; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.servlet.http.HttpServletResponse; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import roomescape.auth.web.support.Admin; -import roomescape.auth.web.support.LoginRequired; -import roomescape.common.dto.response.RoomescapeApiResponse; -import roomescape.common.dto.response.RoomescapeErrorResponse; -import roomescape.reservation.business.ReservationTimeService; +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.Schema +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.responses.ApiResponses +import jakarta.servlet.http.HttpServletResponse +import jakarta.validation.Valid +import jakarta.validation.constraints.NotNull +import org.springframework.http.HttpHeaders +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.* +import roomescape.auth.web.support.Admin +import roomescape.auth.web.support.LoginRequired +import roomescape.common.dto.response.CommonApiResponse +import roomescape.common.dto.response.RoomescapeApiResponse +import roomescape.common.dto.response.RoomescapeApiResponse.Companion.success +import roomescape.common.dto.response.RoomescapeErrorResponse +import roomescape.reservation.business.ReservationTimeService +import roomescape.reservation.docs.ReservationTimeAPI +import java.net.URI +import java.time.LocalDate @RestController -@Tag(name = "4. 예약 시간 API", description = "예약 시간을 조회 / 추가 / 삭제할 때 사용합니다.") -public class ReservationTimeController { +class ReservationTimeController( + private val reservationTimeService: ReservationTimeService +) : ReservationTimeAPI { - private final ReservationTimeService reservationTimeService; + @GetMapping("/times") + override fun getAllTimes(): ResponseEntity> { + val response: ReservationTimesResponse = reservationTimeService.findAllTimes() - public ReservationTimeController(ReservationTimeService reservationTimeService) { - this.reservationTimeService = reservationTimeService; - } + return ResponseEntity.ok(CommonApiResponse(response)) + } - @Admin - @GetMapping("/times") - @ResponseStatus(HttpStatus.OK) - @Operation(summary = "모든 시간 조회", tags = "관리자 로그인이 필요한 API") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true) - }) - public RoomescapeApiResponse getAllTimes() { - return RoomescapeApiResponse.success(reservationTimeService.findAllTimes()); - } + @PostMapping("/times") + override fun saveTime( + @Valid @RequestBody reservationTimeRequest: ReservationTimeRequest, + ): ResponseEntity> { + val response: ReservationTimeResponse = reservationTimeService.addTime(reservationTimeRequest) - @Admin - @PostMapping("/times") - @ResponseStatus(HttpStatus.CREATED) - @Operation(summary = "시간 추가", tags = "관리자 로그인이 필요한 API") - @ApiResponses({ - @ApiResponse(responseCode = "201", description = "성공", useReturnTypeSchema = true), - @ApiResponse(responseCode = "409", description = "같은 시간을 추가할 수 없습니다.", - content = @Content(schema = @Schema(implementation = RoomescapeErrorResponse.class))) - }) - public RoomescapeApiResponse saveTime( - @Valid @RequestBody ReservationTimeRequest reservationTimeRequest, - HttpServletResponse response - ) { - ReservationTimeResponse reservationTimeResponse = reservationTimeService.addTime(reservationTimeRequest); - response.setHeader(HttpHeaders.LOCATION, "/times/" + reservationTimeResponse.id); + return ResponseEntity + .created(URI.create("/times/${response.id}")) + .body(CommonApiResponse(response)) + } - return RoomescapeApiResponse.success(reservationTimeResponse); - } + @DeleteMapping("/times/{id}") + override fun removeTime(@PathVariable id: Long): ResponseEntity> { + reservationTimeService.removeTimeById(id) - @Admin - @DeleteMapping("/times/{id}") - @ResponseStatus(HttpStatus.NO_CONTENT) - @Operation(summary = "시간 삭제", tags = "관리자 로그인이 필요한 API") - @ApiResponses({ - @ApiResponse(responseCode = "204", description = "성공", useReturnTypeSchema = true), - @ApiResponse(responseCode = "409", description = "예약된 시간은 삭제할 수 없습니다.", - content = @Content(schema = @Schema(implementation = RoomescapeErrorResponse.class))) - }) - public RoomescapeApiResponse removeTime( - @NotNull(message = "timeId는 null 또는 공백일 수 없습니다.") @PathVariable @Parameter(description = "삭제하고자 하는 시간의 ID값") Long id - ) { - reservationTimeService.removeTimeById(id); + return ResponseEntity.noContent().build() + } - return RoomescapeApiResponse.success(); - } + @GetMapping("/times/filter") + override fun findAllAvailableReservationTimes( + @RequestParam date: LocalDate, + @RequestParam themeId: Long + ): ResponseEntity> { + val response: ReservationTimeInfosResponse = reservationTimeService.findAllAvailableTimesByDateAndTheme(date, themeId) - @LoginRequired - @GetMapping("/times/filter") - @ResponseStatus(HttpStatus.OK) - @Operation(summary = "예약 가능 여부를 포함한 모든 시간 조회", tags = "로그인이 필요한 API") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true) - }) - public RoomescapeApiResponse findAllAvailableReservationTimes( - @NotNull(message = "날짜는 null일 수 없습니다.") - @RequestParam - @Parameter(description = "yyyy-MM-dd 형식으로 입력해주세요.", example = "2024-06-10") - LocalDate date, - @NotNull(message = "themeId는 null일 수 없습니다.") - @RequestParam - @Parameter(description = "조회할 테마의 ID를 입력해주세요.", example = "1") - Long themeId - ) { - return RoomescapeApiResponse.success(reservationTimeService.findAllAvailableTimesByDateAndTheme(date, themeId)); - } + return ResponseEntity.ok(CommonApiResponse(response)) + } }