[#7] API 응답 형식 재정의 및 Swagger-UI 관련 코드 패키지 분리 #8

Merged
pricelees merged 16 commits from refactor/#7 into main 2025-07-15 05:37:42 +00:00
Showing only changes of commit 63f0eac1bb - Show all commits

View File

@ -1,158 +1,158 @@
package roomescape.common.dto.response
import com.fasterxml.jackson.databind.ObjectMapper
import com.ninjasquad.springmockk.MockkBean
import com.ninjasquad.springmockk.SpykBean
import io.kotest.core.spec.style.BehaviorSpec
import org.hamcrest.CoreMatchers.equalTo
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
import org.springframework.http.MediaType
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.get
import org.springframework.test.web.servlet.post
import org.springframework.web.bind.annotation.*
import roomescape.auth.infrastructure.jwt.JwtHandler
import roomescape.auth.web.support.AdminInterceptor
import roomescape.auth.web.support.LoginInterceptor
import roomescape.auth.web.support.MemberIdResolver
import roomescape.common.exception.ErrorType
import roomescape.member.business.MemberService
import roomescape.member.infrastructure.persistence.MemberRepository
@WebMvcTest(ApiResponseTestController::class)
class RoomescapeApiResponseKTTest(
@Autowired private val mockMvc: MockMvc
) : BehaviorSpec() {
@Autowired
private lateinit var AdminInterceptor: AdminInterceptor
@Autowired
private lateinit var loginInterceptor: LoginInterceptor
@Autowired
private lateinit var memberIdResolver: MemberIdResolver
@SpykBean
private lateinit var memberService: MemberService
@MockkBean
private lateinit var memberRepository: MemberRepository
@MockkBean
private lateinit var jwtHandler: JwtHandler
init {
Given("성공 응답에") {
val endpoint = "/success"
When("객체 데이터를 담으면") {
val id: Long = 1L
val name = "name"
Then("success=true, data={객체} 형태로 응답한다.") {
mockMvc.post("$endpoint/$id/$name") {
contentType = MediaType.APPLICATION_JSON
}.andDo {
print()
}.andExpect {
status { isOk() }
jsonPath("$.success", equalTo(true))
jsonPath("$.data.id", equalTo(id.toInt()))
jsonPath("$.data.name", equalTo(name))
}
}
}
When("문자열 데이터를 담으면") {
val message: String = "Hello, World!"
Then("success=true, data={문자열} 형태로 응답한다.") {
mockMvc.get("/success/$message") {
contentType = MediaType.APPLICATION_JSON
}.andDo {
print()
}.andExpect {
status { isOk() }
jsonPath("$.success", equalTo(true))
jsonPath("$.data", equalTo(message))
}
}
}
}
Given("실패 응답에") {
val endpoint = "/fail"
val objectMapper = ObjectMapper()
When("errorType만 담으면") {
Then("success=false, errorType={errorType}, message={errorType.description} 형태로 응답한다.") {
mockMvc.post(endpoint) {
contentType = MediaType.APPLICATION_JSON
content = objectMapper.writeValueAsString(FailRequest(errorType = ErrorType.INTERNAL_SERVER_ERROR))
}.andDo {
print()
}.andExpect {
status { isOk() }
jsonPath("$.success", equalTo(false))
jsonPath("$.errorType", equalTo(ErrorType.INTERNAL_SERVER_ERROR.name))
jsonPath("$.message", equalTo(ErrorType.INTERNAL_SERVER_ERROR.description))
}
}
}
When("errorType과 message를 담으면") {
val message: String = "An error occurred"
Then("success=false, errorType={errorType}, message={message} 형태로 응답한다.") {
mockMvc.post(endpoint) {
contentType = MediaType.APPLICATION_JSON
content = objectMapper.writeValueAsString(FailRequest(errorType = ErrorType.INTERNAL_SERVER_ERROR, message = message))
}.andDo {
print()
}.andExpect {
status { isOk() }
jsonPath("$.success", equalTo(false))
jsonPath("$.errorType", equalTo(ErrorType.INTERNAL_SERVER_ERROR.name))
jsonPath("$.message", equalTo(message))
}
}
}
}
}
}
data class SuccessResponse(
val id: Long,
val name: String
)
data class FailRequest(
val errorType: ErrorType,
val message: String? = null
)
@RestController
class ApiResponseTestController {
@GetMapping("/success/{message}")
fun succeedToGet(
@PathVariable message: String,
): RoomescapeApiResponseKT<String> =
RoomescapeApiResponseKT.success(message)
@PostMapping("/success/{id}/{name}")
fun succeedToPost(
@PathVariable id: Long,
@PathVariable name: String,
): RoomescapeApiResponseKT<SuccessResponse> =
RoomescapeApiResponseKT.success(SuccessResponse(id, name))
@PostMapping("/fail")
fun fail(
@RequestBody request: FailRequest
): RoomescapeApiResponseKT<Unit> =
request.message?.let {
RoomescapeApiResponseKT.fail(request.errorType, it)
} ?: RoomescapeApiResponseKT.fail(request.errorType)
}
//package roomescape.common.dto.response
//
//import com.fasterxml.jackson.databind.ObjectMapper
//import com.ninjasquad.springmockk.MockkBean
//import com.ninjasquad.springmockk.SpykBean
//import io.kotest.core.spec.style.BehaviorSpec
//import org.hamcrest.CoreMatchers.equalTo
//import org.springframework.beans.factory.annotation.Autowired
//import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
//import org.springframework.http.MediaType
//import org.springframework.test.web.servlet.MockMvc
//import org.springframework.test.web.servlet.get
//import org.springframework.test.web.servlet.post
//import org.springframework.web.bind.annotation.*
//import roomescape.auth.infrastructure.jwt.JwtHandler
//import roomescape.auth.web.support.AdminInterceptor
//import roomescape.auth.web.support.LoginInterceptor
//import roomescape.auth.web.support.MemberIdResolver
//import roomescape.common.exception.ErrorType
//import roomescape.member.business.MemberService
//import roomescape.member.infrastructure.persistence.MemberRepository
//
//@WebMvcTest(ApiResponseTestController::class)
//class RoomescapeApiResponseKTTest(
// @Autowired private val mockMvc: MockMvc
//) : BehaviorSpec() {
// @Autowired
// private lateinit var AdminInterceptor: AdminInterceptor
//
// @Autowired
// private lateinit var loginInterceptor: LoginInterceptor
//
// @Autowired
// private lateinit var memberIdResolver: MemberIdResolver
//
// @SpykBean
// private lateinit var memberService: MemberService
//
// @MockkBean
// private lateinit var memberRepository: MemberRepository
//
// @MockkBean
// private lateinit var jwtHandler: JwtHandler
//
// init {
// Given("성공 응답에") {
// val endpoint = "/success"
// When("객체 데이터를 담으면") {
// val id: Long = 1L
// val name = "name"
// Then("success=true, data={객체} 형태로 응답한다.") {
// mockMvc.post("$endpoint/$id/$name") {
// contentType = MediaType.APPLICATION_JSON
// }.andDo {
// print()
// }.andExpect {
// status { isOk() }
// jsonPath("$.success", equalTo(true))
// jsonPath("$.data.id", equalTo(id.toInt()))
// jsonPath("$.data.name", equalTo(name))
// }
// }
// }
//
// When("문자열 데이터를 담으면") {
// val message: String = "Hello, World!"
//
// Then("success=true, data={문자열} 형태로 응답한다.") {
// mockMvc.get("/success/$message") {
// contentType = MediaType.APPLICATION_JSON
// }.andDo {
// print()
// }.andExpect {
// status { isOk() }
// jsonPath("$.success", equalTo(true))
// jsonPath("$.data", equalTo(message))
// }
// }
// }
// }
//
// Given("실패 응답에") {
// val endpoint = "/fail"
// val objectMapper = ObjectMapper()
//
// When("errorType만 담으면") {
// Then("success=false, errorType={errorType}, message={errorType.description} 형태로 응답한다.") {
// mockMvc.post(endpoint) {
// contentType = MediaType.APPLICATION_JSON
// content = objectMapper.writeValueAsString(FailRequest(errorType = ErrorType.INTERNAL_SERVER_ERROR))
// }.andDo {
// print()
// }.andExpect {
// status { isOk() }
// jsonPath("$.success", equalTo(false))
// jsonPath("$.errorType", equalTo(ErrorType.INTERNAL_SERVER_ERROR.name))
// jsonPath("$.message", equalTo(ErrorType.INTERNAL_SERVER_ERROR.description))
// }
// }
// }
//
// When("errorType과 message를 담으면") {
// val message: String = "An error occurred"
//
// Then("success=false, errorType={errorType}, message={message} 형태로 응답한다.") {
// mockMvc.post(endpoint) {
// contentType = MediaType.APPLICATION_JSON
// content = objectMapper.writeValueAsString(FailRequest(errorType = ErrorType.INTERNAL_SERVER_ERROR, message = message))
// }.andDo {
// print()
// }.andExpect {
// status { isOk() }
// jsonPath("$.success", equalTo(false))
// jsonPath("$.errorType", equalTo(ErrorType.INTERNAL_SERVER_ERROR.name))
// jsonPath("$.message", equalTo(message))
// }
// }
// }
// }
// }
//}
//
//data class SuccessResponse(
// val id: Long,
// val name: String
//)
//
//data class FailRequest(
// val errorType: ErrorType,
// val message: String? = null
//)
//
//@RestController
//class ApiResponseTestController {
//
// @GetMapping("/success/{message}")
// fun succeedToGet(
// @PathVariable message: String,
// ): RoomescapeApiResponseKT<String> =
// RoomescapeApiResponseKT.success(message)
//
//
// @PostMapping("/success/{id}/{name}")
// fun succeedToPost(
// @PathVariable id: Long,
// @PathVariable name: String,
// ): RoomescapeApiResponseKT<SuccessResponse> =
// RoomescapeApiResponseKT.success(SuccessResponse(id, name))
//
//
// @PostMapping("/fail")
// fun fail(
// @RequestBody request: FailRequest
// ): RoomescapeApiResponseKT<Unit> =
// request.message?.let {
// RoomescapeApiResponseKT.fail(request.errorType, it)
// } ?: RoomescapeApiResponseKT.fail(request.errorType)
//}