diff --git a/server/api/src/main/kotlin/com/kw/api/common/dto/response/ErrorResponse.kt b/server/api/src/main/kotlin/com/kw/api/common/dto/response/ErrorResponse.kt index c3b712c..52a1c03 100644 --- a/server/api/src/main/kotlin/com/kw/api/common/dto/response/ErrorResponse.kt +++ b/server/api/src/main/kotlin/com/kw/api/common/dto/response/ErrorResponse.kt @@ -2,5 +2,11 @@ package com.kw.api.common.dto.response class ErrorResponse( val code: String, - val message: String -) + val message: String, + val validations: MutableMap = mutableMapOf() +) { + fun addValidation(key: String, value: String) { + validations[key] = value + } + +} diff --git a/server/api/src/main/kotlin/com/kw/api/common/exception/CustomErrorCode.kt b/server/api/src/main/kotlin/com/kw/api/common/exception/CustomErrorCode.kt index 52a0a54..9ce1ee3 100644 --- a/server/api/src/main/kotlin/com/kw/api/common/exception/CustomErrorCode.kt +++ b/server/api/src/main/kotlin/com/kw/api/common/exception/CustomErrorCode.kt @@ -8,10 +8,18 @@ enum class CustomErrorCode( val message: String ) { + // bundle FORBIDDEN_BUNDLE(HttpStatus.FORBIDDEN, "FORBIDDEN_BUNDLE", "비공개 꾸러미입니다."), NOT_FOUND_BUNDLE(HttpStatus.NOT_FOUND, "NOT_FOUND_BUNDLE", "존재하지 않는 꾸러미입니다."), + + // question NOT_FOUND_QUESTION(HttpStatus.NOT_FOUND, "NOT_FOUND_QUESTION", "존재하지 않는 질문입니다."), + INCLUDE_NOT_FOUND_QUESTION(HttpStatus.NOT_FOUND, "INCLUDE_NOT_FOUND_QUESTION", "존재하지 않는 질문이 포함되어 있습니다."), + // tag INCLUDE_NOT_FOUND_TAG(HttpStatus.NOT_FOUND, "INCLUDE_NOT_FOUND_TAG", "존재하지 않는 태그가 포함되어 있습니다."), - INCLUDE_NOT_FOUND_QUESTION(HttpStatus.NOT_FOUND, "INCLUDE_NOT_FOUND_QUESTION", "존재하지 않는 질문이 포함되어 있습니다."), + + // common + BAD_REQUEST(HttpStatus.BAD_REQUEST, "BAD_REQUEST", "잘못된 요청입니다."), + } diff --git a/server/api/src/main/kotlin/com/kw/api/common/exception/CustomExceptionHandler.kt b/server/api/src/main/kotlin/com/kw/api/common/exception/CustomExceptionHandler.kt index af71d1c..0ef2a67 100644 --- a/server/api/src/main/kotlin/com/kw/api/common/exception/CustomExceptionHandler.kt +++ b/server/api/src/main/kotlin/com/kw/api/common/exception/CustomExceptionHandler.kt @@ -1,14 +1,46 @@ package com.kw.api.common.exception import com.kw.api.common.dto.response.ErrorResponse +import org.springframework.http.HttpHeaders +import org.springframework.http.HttpStatusCode import org.springframework.http.ResponseEntity +import org.springframework.http.converter.HttpMessageNotReadableException +import org.springframework.web.bind.MethodArgumentNotValidException import org.springframework.web.bind.annotation.ExceptionHandler import org.springframework.web.bind.annotation.RestControllerAdvice +import org.springframework.web.context.request.WebRequest import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler @RestControllerAdvice class CustomExceptionHandler : ResponseEntityExceptionHandler() { + override fun handleHttpMessageNotReadable( + ex: HttpMessageNotReadableException, + headers: HttpHeaders, + status: HttpStatusCode, + request: WebRequest + ): ResponseEntity? { + val errorCode = CustomErrorCode.BAD_REQUEST + val errorResponse = ErrorResponse(errorCode.code, errorCode.message) + return ResponseEntity.status(errorCode.status).body(errorResponse) + } + + override fun handleMethodArgumentNotValid( + ex: MethodArgumentNotValidException, + headers: HttpHeaders, + status: HttpStatusCode, + request: WebRequest + ): ResponseEntity? { + val errorCode = CustomErrorCode.BAD_REQUEST + val errorResponse = ErrorResponse(errorCode.code, errorCode.message) + + ex.bindingResult.fieldErrors.forEach { + errorResponse.addValidation(it.field, it.defaultMessage!!) + } + + return ResponseEntity.status(errorCode.status).body(errorResponse) + } + @ExceptionHandler(CustomException::class) protected fun handleCustomException(ex: CustomException): ResponseEntity { return ResponseEntity.status(ex.getStatus()).body(ex.getErrorResponse()) diff --git a/server/api/src/main/kotlin/com/kw/api/domain/bundle/dto/request/BundleCreateRequest.kt b/server/api/src/main/kotlin/com/kw/api/domain/bundle/dto/request/BundleCreateRequest.kt index cade8c7..4132277 100644 --- a/server/api/src/main/kotlin/com/kw/api/domain/bundle/dto/request/BundleCreateRequest.kt +++ b/server/api/src/main/kotlin/com/kw/api/domain/bundle/dto/request/BundleCreateRequest.kt @@ -1,17 +1,17 @@ package com.kw.api.domain.bundle.dto.request import com.kw.data.domain.bundle.Bundle -import jakarta.validation.constraints.Max import jakarta.validation.constraints.NotBlank +import jakarta.validation.constraints.Size data class BundleCreateRequest( - @NotBlank(message = "이름은 필수입니다.") + @field:NotBlank(message = "이름은 필수입니다.") val name: String, - @NotBlank(message = "공개 범위 설정은 필수입니다.") + @field:NotBlank(message = "공개 범위 설정은 필수입니다.") val shareType: String, - @Max(value = 3, message = "태그는 최대 3개까지 지정 가능합니다.") + @field:Size(max = 3, message = "태그는 최대 3개까지 지정 가능합니다.") val tagIds: List? ) { fun toEntity(): Bundle { diff --git a/server/api/src/main/kotlin/com/kw/api/domain/bundle/dto/request/BundleQuestionAddRequest.kt b/server/api/src/main/kotlin/com/kw/api/domain/bundle/dto/request/BundleQuestionAddRequest.kt index 1fabfc9..250a3ab 100644 --- a/server/api/src/main/kotlin/com/kw/api/domain/bundle/dto/request/BundleQuestionAddRequest.kt +++ b/server/api/src/main/kotlin/com/kw/api/domain/bundle/dto/request/BundleQuestionAddRequest.kt @@ -1,3 +1,8 @@ package com.kw.api.domain.bundle.dto.request -data class BundleQuestionAddRequest(val questionIds: List) +import jakarta.validation.constraints.Size + +data class BundleQuestionAddRequest( + @field:Size(min = 1, message = "추가할 질문을 선택해 주세요.") + val questionIds: List +) diff --git a/server/api/src/main/kotlin/com/kw/api/domain/bundle/dto/request/BundleQuestionOrderListUpdateRequest.kt b/server/api/src/main/kotlin/com/kw/api/domain/bundle/dto/request/BundleQuestionOrderListUpdateRequest.kt deleted file mode 100644 index 5004ee6..0000000 --- a/server/api/src/main/kotlin/com/kw/api/domain/bundle/dto/request/BundleQuestionOrderListUpdateRequest.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.kw.api.domain.bundle.dto.request - -//data class BundleQuestionOrderListUpdateRequest() diff --git a/server/api/src/main/kotlin/com/kw/api/domain/bundle/dto/request/BundleQuestionRemoveRequest.kt b/server/api/src/main/kotlin/com/kw/api/domain/bundle/dto/request/BundleQuestionRemoveRequest.kt index a4511e2..f4ecbeb 100644 --- a/server/api/src/main/kotlin/com/kw/api/domain/bundle/dto/request/BundleQuestionRemoveRequest.kt +++ b/server/api/src/main/kotlin/com/kw/api/domain/bundle/dto/request/BundleQuestionRemoveRequest.kt @@ -1,3 +1,8 @@ package com.kw.api.domain.bundle.dto.request -data class BundleQuestionRemoveRequest(val questionIds: List) +import jakarta.validation.constraints.Size + +data class BundleQuestionRemoveRequest( + @field:Size(min = 1, message = "삭제할 질문을 선택해 주세요.") + val questionIds: List +) diff --git a/server/api/src/main/kotlin/com/kw/api/domain/bundle/dto/request/BundleUpdateRequest.kt b/server/api/src/main/kotlin/com/kw/api/domain/bundle/dto/request/BundleUpdateRequest.kt index 61f0962..a432188 100644 --- a/server/api/src/main/kotlin/com/kw/api/domain/bundle/dto/request/BundleUpdateRequest.kt +++ b/server/api/src/main/kotlin/com/kw/api/domain/bundle/dto/request/BundleUpdateRequest.kt @@ -1,15 +1,7 @@ package com.kw.api.domain.bundle.dto.request -import jakarta.validation.constraints.Max -import jakarta.validation.constraints.NotBlank - data class BundleUpdateRequest( - @NotBlank(message = "이름은 필수입니다.") val name: String?, - - @NotBlank(message = "공개 범위 설정은 필수입니다.") val shareType: String?, - - @Max(value = 3, message = "태그는 최대 3개까지 지정 가능합니다.") val tagIds: List? ) diff --git a/server/api/src/main/kotlin/com/kw/api/domain/question/controller/QuestionController.kt b/server/api/src/main/kotlin/com/kw/api/domain/question/controller/QuestionController.kt index 83c692d..776d677 100644 --- a/server/api/src/main/kotlin/com/kw/api/domain/question/controller/QuestionController.kt +++ b/server/api/src/main/kotlin/com/kw/api/domain/question/controller/QuestionController.kt @@ -18,7 +18,7 @@ class QuestionController(val questionService: QuestionService) { @ResponseStatus(HttpStatus.CREATED) @PostMapping("/questions") - fun createQuestion(@RequestBody request: QuestionCreateRequest): ApiResponse { + fun createQuestion(@RequestBody @Valid request: QuestionCreateRequest): ApiResponse { val response = questionService.createQuestion(request) return ApiResponse.created(response); } diff --git a/server/api/src/main/kotlin/com/kw/api/domain/question/dto/request/QuestionAnswerRequest.kt b/server/api/src/main/kotlin/com/kw/api/domain/question/dto/request/QuestionAnswerRequest.kt deleted file mode 100644 index 24da60f..0000000 --- a/server/api/src/main/kotlin/com/kw/api/domain/question/dto/request/QuestionAnswerRequest.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.kw.api.domain.question.dto.request - -data class QuestionAnswerRequest( - val answer : String -) diff --git a/server/api/src/main/kotlin/com/kw/api/domain/question/dto/request/QuestionCreateRequest.kt b/server/api/src/main/kotlin/com/kw/api/domain/question/dto/request/QuestionCreateRequest.kt index b8d0171..4db3045 100644 --- a/server/api/src/main/kotlin/com/kw/api/domain/question/dto/request/QuestionCreateRequest.kt +++ b/server/api/src/main/kotlin/com/kw/api/domain/question/dto/request/QuestionCreateRequest.kt @@ -3,20 +3,18 @@ package com.kw.api.domain.question.dto.request import com.kw.data.domain.bundle.Bundle import com.kw.data.domain.question.Question import jakarta.validation.constraints.NotBlank -import jakarta.validation.constraints.NotNull data class QuestionCreateRequest( - @NotBlank(message = "내용은 필수입니다.") + @field:NotBlank(message = "내용은 필수입니다.") val content: String, val answer: String?, - @NotBlank(message = "답변 공개 범위 설정은 필수입니다.") + @field:NotBlank(message = "답변 공개 범위 설정은 필수입니다.") val answerShareStatus: String, val tagIds: List?, - @NotNull(message = "꾸러미 선택은 필수입니다.") val bundleId: Long ) { fun toEntity(bundle: Bundle): Question {