-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #9 from Team-Going/feature/3
ISSUE-3 API 응답 Spec & 예외 Setting
- Loading branch information
Showing
8 changed files
with
237 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package org.doorip.core | ||
|
||
import org.doorip.domain.InvalidRequestValueException | ||
import org.springframework.stereotype.Service | ||
|
||
@Service | ||
class TestService { | ||
|
||
fun throwDooripException() { | ||
throw InvalidRequestValueException | ||
} | ||
} |
47 changes: 47 additions & 0 deletions
47
domain/src/main/kotlin/org/doorip/domain/DooripException.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package org.doorip.domain | ||
|
||
sealed class DooripException( | ||
val code: String, | ||
message: String, | ||
cause: Throwable? = null, | ||
) : RuntimeException(message, cause) | ||
|
||
// Client Exception | ||
sealed class ClientException( | ||
code: String, | ||
message: String, | ||
) : DooripException(code, message) | ||
|
||
class UnauthorizedException( | ||
code: String, | ||
message: String, | ||
) : ClientException(code, message) | ||
|
||
class UnauthenticatedException( | ||
code: String, | ||
message: String, | ||
) : ClientException(code, message) | ||
|
||
data object InvalidRequestValueException : ClientException("e4000", "잘못된 요청입니다.") { private fun readResolve(): Any = InvalidRequestValueException } | ||
data object MethodNotAllowedException : ClientException("e4050", "잘못된 HTTP method 요청입니다.") { private fun readResolve(): Any = MethodNotAllowedException } | ||
data object ConflictException : ClientException("e4090", "이미 존재하는 리소스입니다.") { private fun readResolve(): Any = ConflictException } | ||
|
||
// Server Exception | ||
sealed class ServerException( | ||
code: String, | ||
message: String, | ||
) : DooripException(code, message) | ||
|
||
data object NotFoundException : ServerException("e4040", "대상을 찾을 수 없습니다.") { private fun readResolve(): Any = NotFoundException } | ||
data object InternalServerException : ServerException("e5000", "서버 내부 오류입니다.") { private fun readResolve(): Any = InternalServerException } | ||
|
||
// Critical Exception | ||
sealed class CriticalException( | ||
code: String, | ||
message: String, | ||
cause: Throwable? = null, | ||
) : DooripException(code, message, cause) | ||
|
||
class UnknownException( | ||
cause: Throwable? = null, | ||
) : CriticalException("e6000", "정의되지 않은 예외입니다. (로그 확인이 필요합니다.)", cause) |
11 changes: 0 additions & 11 deletions
11
presentation/api/src/main/kotlin/org/doorip/TestController.kt
This file was deleted.
Oops, something went wrong.
29 changes: 29 additions & 0 deletions
29
presentation/api/src/main/kotlin/org/doorip/api/TestController.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package org.doorip.api | ||
|
||
import org.doorip.api.dto.ApiResponse | ||
import org.doorip.core.TestService | ||
import org.springframework.http.ResponseEntity | ||
import org.springframework.stereotype.Controller | ||
import org.springframework.web.bind.annotation.GetMapping | ||
import org.springframework.web.bind.annotation.ResponseBody | ||
|
||
@Controller | ||
class TestController( | ||
private val testService: TestService, | ||
) { | ||
|
||
@ResponseBody | ||
@GetMapping("/api/test") | ||
fun test() = "doorip ok" | ||
|
||
@GetMapping("/api/test/ok") | ||
fun ok(): ResponseEntity<ApiResponse<Unit>> { | ||
return ApiResponse.ok() | ||
} | ||
|
||
@ResponseBody | ||
@GetMapping("/api/test/ex") | ||
fun exception() { | ||
testService.throwDooripException() | ||
} | ||
} |
38 changes: 38 additions & 0 deletions
38
presentation/api/src/main/kotlin/org/doorip/api/dto/ApiResponse.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package org.doorip.api.dto | ||
|
||
import org.springframework.http.HttpStatus | ||
import org.springframework.http.ResponseEntity | ||
|
||
data class ApiResponse<T>( | ||
val status: Int, | ||
val code: String, | ||
val message: String, | ||
val data: T?, | ||
) { | ||
|
||
companion object { | ||
fun <T> ok( | ||
data: T? = null, | ||
): ResponseEntity<ApiResponse<T>> = ResponseEntity.ok( | ||
ApiResponse( | ||
status = 200, | ||
code = "s2000", | ||
message = "요청이 성공했습니다.", | ||
data = data, | ||
), | ||
) | ||
|
||
fun <T> created( | ||
data: T? = null, | ||
): ResponseEntity<ApiResponse<T>> = ResponseEntity.status( | ||
HttpStatus.CREATED, | ||
).body( | ||
ApiResponse( | ||
status = 201, | ||
code = "s2010", | ||
message = "요청이 성공했습니다.", | ||
data = data, | ||
), | ||
) | ||
} | ||
} |
7 changes: 7 additions & 0 deletions
7
presentation/api/src/main/kotlin/org/doorip/api/dto/ExceptionResponse.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package org.doorip.api.dto | ||
|
||
data class ExceptionResponse( | ||
val status: Int, | ||
val code: String, | ||
val message: String?, | ||
) |
58 changes: 58 additions & 0 deletions
58
presentation/api/src/main/kotlin/org/doorip/api/exception/ApiExceptionHandler.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
package org.doorip.api.exception | ||
|
||
import org.doorip.api.dto.ExceptionResponse | ||
import org.doorip.domain.DooripException | ||
import org.doorip.domain.InvalidRequestValueException | ||
import org.doorip.domain.MethodNotAllowedException | ||
import org.doorip.domain.UnknownException | ||
import org.springframework.http.ResponseEntity | ||
import org.springframework.validation.BindException | ||
import org.springframework.web.HttpRequestMethodNotSupportedException | ||
import org.springframework.web.bind.MethodArgumentNotValidException | ||
import org.springframework.web.bind.annotation.ControllerAdvice | ||
import org.springframework.web.bind.annotation.ExceptionHandler | ||
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException | ||
import org.springframework.web.servlet.resource.NoResourceFoundException | ||
|
||
typealias ExceptionResponseEntity = ResponseEntity<ExceptionResponse> | ||
|
||
@ControllerAdvice | ||
internal class ApiExceptionHandler( | ||
private val exceptionResponseFactory: ExceptionResponseFactory, | ||
) { | ||
|
||
@ExceptionHandler(MethodArgumentTypeMismatchException::class) | ||
protected fun handleException(ex: MethodArgumentTypeMismatchException): ExceptionResponseEntity { | ||
return exceptionResponseFactory.create(InvalidRequestValueException) | ||
} | ||
|
||
@ExceptionHandler(MethodArgumentNotValidException::class) | ||
protected fun handleException(ex: MethodArgumentNotValidException): ExceptionResponseEntity { | ||
return exceptionResponseFactory.create(InvalidRequestValueException) | ||
} | ||
|
||
@ExceptionHandler(BindException::class) | ||
protected fun handleException(ex: BindException): ExceptionResponseEntity { | ||
return exceptionResponseFactory.create(InvalidRequestValueException) | ||
} | ||
|
||
@ExceptionHandler(NoResourceFoundException::class) | ||
protected fun handleException(ex: NoResourceFoundException): ExceptionResponseEntity { | ||
return exceptionResponseFactory.create(InvalidRequestValueException) | ||
} | ||
|
||
@ExceptionHandler(HttpRequestMethodNotSupportedException::class) | ||
protected fun handleException(ex: HttpRequestMethodNotSupportedException): ExceptionResponseEntity { | ||
return exceptionResponseFactory.create(MethodNotAllowedException) | ||
} | ||
|
||
@ExceptionHandler(DooripException::class) | ||
protected fun handleException(ex: DooripException): ExceptionResponseEntity { | ||
return exceptionResponseFactory.create(ex) | ||
} | ||
|
||
@ExceptionHandler(Exception::class) | ||
protected fun handleException(ex: Exception): ExceptionResponseEntity { | ||
return exceptionResponseFactory.create(UnknownException(ex)) | ||
} | ||
} |
46 changes: 46 additions & 0 deletions
46
presentation/api/src/main/kotlin/org/doorip/api/exception/ExceptionResponseFactory.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package org.doorip.api.exception | ||
|
||
import org.doorip.api.dto.ExceptionResponse | ||
import org.doorip.domain.ClientException | ||
import org.doorip.domain.ConflictException | ||
import org.doorip.domain.CriticalException | ||
import org.doorip.domain.DooripException | ||
import org.doorip.domain.MethodNotAllowedException | ||
import org.doorip.domain.NotFoundException | ||
import org.doorip.domain.ServerException | ||
import org.doorip.domain.UnauthenticatedException | ||
import org.doorip.domain.UnauthorizedException | ||
import org.springframework.http.HttpStatus | ||
import org.springframework.http.ResponseEntity | ||
import org.springframework.stereotype.Component | ||
|
||
@Component | ||
internal class ExceptionResponseFactory { | ||
|
||
fun create(exception: DooripException): ResponseEntity<ExceptionResponse> { | ||
val httpStatus = exception.getHttpStatus() | ||
|
||
val exceptionResponse = ExceptionResponse( | ||
status = httpStatus.value(), | ||
code = exception.code, | ||
message = exception.message, | ||
) | ||
|
||
return ResponseEntity.status(httpStatus) | ||
.body(exceptionResponse) | ||
} | ||
} | ||
|
||
internal fun DooripException.getHttpStatus(): HttpStatus = | ||
when (this) { | ||
is UnauthorizedException -> HttpStatus.FORBIDDEN | ||
is UnauthenticatedException -> HttpStatus.UNAUTHORIZED | ||
|
||
MethodNotAllowedException -> HttpStatus.METHOD_NOT_ALLOWED | ||
ConflictException -> HttpStatus.CONFLICT | ||
|
||
NotFoundException -> HttpStatus.NOT_FOUND | ||
|
||
is ClientException -> HttpStatus.BAD_REQUEST | ||
is ServerException, is CriticalException -> HttpStatus.INTERNAL_SERVER_ERROR | ||
} |