[#20] 도메인별 예외 분리 #21

Merged
pricelees merged 37 commits from refactor/#20 into main 2025-07-24 02:48:53 +00:00
4 changed files with 37 additions and 19 deletions
Showing only changes of commit 9683ed946e - Show all commits

View File

@ -7,9 +7,11 @@ enum class AuthErrorCode(
override val httpStatus: HttpStatus, override val httpStatus: HttpStatus,
override val errorCode: String, override val errorCode: String,
override val message: String, override val message: String,
): ErrorCode { ) : ErrorCode {
TOKEN_NOT_FOUND(HttpStatus.UNAUTHORIZED, "A001", "인증 토큰이 없어요."), TOKEN_NOT_FOUND(HttpStatus.UNAUTHORIZED, "A001", "인증 토큰이 없어요."),
INVALID_TOKEN(HttpStatus.UNAUTHORIZED, "A002", "유효하지 않은 토큰이에요."), INVALID_TOKEN(HttpStatus.UNAUTHORIZED, "A002", "유효하지 않은 토큰이에요."),
EXPIRED_TOKEN(HttpStatus.UNAUTHORIZED, "A003", "토큰이 만료됐어요."), EXPIRED_TOKEN(HttpStatus.UNAUTHORIZED, "A003", "토큰이 만료됐어요."),
ACCESS_DENIED(HttpStatus.FORBIDDEN, "A004", "접근 권한이 없어요."), ACCESS_DENIED(HttpStatus.FORBIDDEN, "A004", "접근 권한이 없어요."),
LOGIN_FAILED(HttpStatus.UNAUTHORIZED, "A005", "이메일과 비밀번호를 확인해주세요."),
UNIDENTIFIABLE_MEMBER(HttpStatus.UNAUTHORIZED, "A006", "회원 정보를 찾을 수 없어요."),
} }

View File

@ -1,6 +1,8 @@
package roomescape.auth.service package roomescape.auth.service
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
import roomescape.auth.exception.AuthErrorCode
import roomescape.auth.exception.AuthException
import roomescape.auth.infrastructure.jwt.JwtHandler import roomescape.auth.infrastructure.jwt.JwtHandler
import roomescape.auth.web.LoginCheckResponse import roomescape.auth.web.LoginCheckResponse
import roomescape.auth.web.LoginRequest import roomescape.auth.web.LoginRequest
@ -14,10 +16,9 @@ class AuthService(
private val jwtHandler: JwtHandler private val jwtHandler: JwtHandler
) { ) {
fun login(request: LoginRequest): LoginResponse { fun login(request: LoginRequest): LoginResponse {
val member: MemberEntity = memberService.findByEmailAndPassword( val member: MemberEntity = fetchMemberOrThrow(AuthErrorCode.LOGIN_FAILED) {
request.email, memberService.findByEmailAndPassword(request.email, request.password)
request.password }
)
val accessToken: String = jwtHandler.createToken(member.id!!) val accessToken: String = jwtHandler.createToken(member.id!!)
@ -25,8 +26,21 @@ class AuthService(
} }
fun checkLogin(memberId: Long): LoginCheckResponse { fun checkLogin(memberId: Long): LoginCheckResponse {
val member = memberService.findById(memberId) val member: MemberEntity = fetchMemberOrThrow(AuthErrorCode.UNIDENTIFIABLE_MEMBER) {
memberService.findById(memberId)
}
return LoginCheckResponse(member.name) return LoginCheckResponse(member.name)
} }
private fun fetchMemberOrThrow(
errorCode: AuthErrorCode,
block: () -> MemberEntity
): MemberEntity {
try {
return block()
} catch (_: Exception) {
throw AuthException(errorCode)
}
}
} }

View File

@ -7,10 +7,10 @@ import io.kotest.matchers.shouldBe
import io.mockk.every import io.mockk.every
import io.mockk.mockk import io.mockk.mockk
import org.springframework.data.repository.findByIdOrNull import org.springframework.data.repository.findByIdOrNull
import roomescape.auth.exception.AuthErrorCode
import roomescape.auth.exception.AuthException
import roomescape.auth.infrastructure.jwt.JwtHandler import roomescape.auth.infrastructure.jwt.JwtHandler
import roomescape.auth.service.AuthService import roomescape.auth.service.AuthService
import roomescape.common.exception.ErrorType
import roomescape.common.exception.RoomescapeException
import roomescape.member.business.MemberService import roomescape.member.business.MemberService
import roomescape.member.infrastructure.persistence.MemberEntity import roomescape.member.infrastructure.persistence.MemberEntity
import roomescape.member.infrastructure.persistence.MemberRepository import roomescape.member.infrastructure.persistence.MemberRepository
@ -45,11 +45,11 @@ class AuthServiceTest : BehaviorSpec({
memberRepository.findByEmailAndPassword(request.email, request.password) memberRepository.findByEmailAndPassword(request.email, request.password)
} returns null } returns null
val exception = shouldThrow<RoomescapeException> { val exception = shouldThrow<AuthException> {
authService.login(request) authService.login(request)
} }
exception.errorType shouldBe ErrorType.MEMBER_NOT_FOUND exception.errorCode shouldBe AuthErrorCode.LOGIN_FAILED
} }
} }
} }
@ -71,11 +71,11 @@ class AuthServiceTest : BehaviorSpec({
Then("회원이 없다면 예외를 던진다.") { Then("회원이 없다면 예외를 던진다.") {
every { memberRepository.findByIdOrNull(userId) } returns null every { memberRepository.findByIdOrNull(userId) } returns null
val exception = shouldThrow<RoomescapeException> { val exception = shouldThrow<AuthException> {
authService.checkLogin(userId) authService.checkLogin(userId)
} }
exception.errorType shouldBe ErrorType.MEMBER_NOT_FOUND exception.errorCode shouldBe AuthErrorCode.UNIDENTIFIABLE_MEMBER
} }
} }
} }

View File

@ -7,10 +7,10 @@ import org.hamcrest.Matchers.equalTo
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
import org.springframework.data.repository.findByIdOrNull import org.springframework.data.repository.findByIdOrNull
import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.MockMvc
import roomescape.auth.exception.AuthErrorCode
import roomescape.auth.service.AuthService import roomescape.auth.service.AuthService
import roomescape.common.exception.CommonErrorCode import roomescape.common.exception.CommonErrorCode
import roomescape.common.exception.ErrorCode import roomescape.common.exception.ErrorCode
import roomescape.common.exception.ErrorType
import roomescape.util.MemberFixture import roomescape.util.MemberFixture
import roomescape.util.RoomescapeApiTest import roomescape.util.RoomescapeApiTest
@ -61,14 +61,15 @@ class AuthControllerTest(
memberRepository.findByEmailAndPassword(userRequest.email, userRequest.password) memberRepository.findByEmailAndPassword(userRequest.email, userRequest.password)
} returns null } returns null
Then("400 에러를 응답한다") { Then("에러 응답") {
val expectedError = AuthErrorCode.LOGIN_FAILED
runPostTest( runPostTest(
mockMvc = mockMvc, mockMvc = mockMvc,
endpoint = endpoint, endpoint = endpoint,
body = userRequest, body = userRequest,
) { ) {
status { isBadRequest() } status { isEqualTo(expectedError.httpStatus.value()) }
jsonPath("$.errorType", equalTo(ErrorType.MEMBER_NOT_FOUND.name)) jsonPath("$.code", equalTo(expectedError.errorCode))
} }
} }
} }
@ -117,13 +118,14 @@ class AuthControllerTest(
every { jwtHandler.getMemberIdFromToken(any()) } returns invalidMemberId every { jwtHandler.getMemberIdFromToken(any()) } returns invalidMemberId
every { memberRepository.findByIdOrNull(invalidMemberId) } returns null every { memberRepository.findByIdOrNull(invalidMemberId) } returns null
Then("400 에러를 응답한다.") { Then("에러 응답.") {
val expectedError = AuthErrorCode.UNIDENTIFIABLE_MEMBER
runGetTest( runGetTest(
mockMvc = mockMvc, mockMvc = mockMvc,
endpoint = endpoint, endpoint = endpoint,
) { ) {
status { isBadRequest() } status { isEqualTo(expectedError.httpStatus.value()) }
jsonPath("$.errorType", equalTo(ErrorType.MEMBER_NOT_FOUND.name)) jsonPath("$.code", equalTo(expectedError.errorCode))
} }
} }
} }