๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿ’ป ๊ฐœ๋ฐœ์ž ์ด์•ผ๊ธฐ/์•ˆ๋“œ๋กœ์ด๋“œ ์‚ฝ์งˆ๊ธฐ

OkHttp ๊ฒฐ๊ณผ ๋ฐ์ดํ„ฐ์˜ ์ค‘๋ณต ๊ฒฐ๊ณผ๊ฐ’๋“ค์„ ํ•˜๋‚˜์˜ data class๋กœ ์ฒ˜๋ฆฌํ•˜๊ธฐ!

by ์ •์„ ํ•œ 2024. 8. 5.
728x90
๋ฐ˜์‘ํ˜•

์ง€๋‚œ Retrofit๊ด€๋ จ ํฌ์ŠคํŒ… ์ดํ›„์—, ๊ณฐ๊ณฐ์ด ์ƒ๊ฐํ•ด ๋ณด๋‹ˆ๊นŒ ๋นผ๋จน์€ ๋‚ด์šฉ์ด ์žˆ๋”๋ผ๊ณ ์š”. ๊ทธ๋ž˜์„œ ์ถ”๊ฐ€๋กœ ํฌ์ŠคํŒ…์„ ๋‚จ๊ฒจ๋ด…๋‹ˆ๋‹ค.

๋ณดํ†ต ๊ฐ™์ด ์ผํ•˜๋Š” ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ์ž ๋ถ„์— ๋”ฐ๋ผ, ํšŒ์‚ฌ ์ •์ฑ…์— ๋”ฐ๋ผ, ๋งŽ์ด ๋ณ€ํ™”๋˜๋Š” ๋ถ€๋ถ„์ธ๋ฐ์š”.
์–ด๋–ค ๊ฒฐ๊ณผ๊ฐ’์„ API์—์„œ ๋„˜๊ฒจ์ฃผ๋А๋ƒ์— ๋”ฐ๋ผ์„œ ์ด ๋‚ด์šฉ์ด ๋„์›€์ด ๋  ์ˆ˜๋„ ์•ˆ๋  ์ˆ˜๋„ ์žˆ๊ฒ ์Šต๋‹ˆ๋‹ค.

ํ…Œ์ŠคํŠธ API์—์„œ๋Š” ๋”ฑํžˆ ํ•„์š” ์—†๋Š” ๋‚ด์šฉ์ด๊ณ , ์ €ํฌ ์‚ฌ๋‚ด API ๊ทœ์น™์—๋Š” ํ•„์š”ํ•œ ๋‚ด์šฉ์ธ๋ฐ์š”.

API๊ฒฐ๊ณผ ๋ฐ์ดํ„ฐ ์ค‘, RESULT ๋ฐ์ดํ„ฐ๊ฐ€ ์•„๋‹Œ Response ๊ตฌ์กฐ๊ฐ€ ์ค‘๋ณต์ฒ˜๋ฆฌ๋  ๋•Œ, ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

์ง€๋‚œ ํฌ์ŠคํŒ…์—์„œ inteceptor๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›๊ธฐ ์ „์— ์—ฌ๋Ÿฌ ์ฒ˜๋ฆฌ๋“ค์„ ํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ๋„ฃ์–ด๋ณด์•˜๋Š”๋ฐ์š”

  • ๋กœ๊ทธ ํ™•์ธ์šฉ
  • ํ—ค๋” ์‚ฝ์ž…์šฉ

์ด๋ฒˆ์—๋Š” ๊ณตํ†ต response ๊ฐ’๋“ค์„ ๋ฌถ์–ด์„œ ํ•˜๋‚˜์˜ ๋ฐ์ดํ„ฐ ํด๋ž˜์Šค๋กœ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

์‚ฌ์‹ค ๊ผญ ํ•ด์ค˜์•ผ ํ•˜๋Š” ๋‚ด์šฉ์€ ์•„๋‹ˆ์ฃ , data class๋ฅผ ๊ทธ๋ƒฅ ์—ฌ๋Ÿฌ ๊ฐœ ๋งŒ๋“ค๊ณ  ๊ณ„์† ์‚ฌ์šฉํ•ด๋„ ๋˜๊ธฐ๋Š” ํ•ฉ๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ์šฐ๋ฆฌ ๋ชจ๋‘ ์ค‘๋ณต๋œ ๋ฐ์ดํ„ฐ ์ข‹์•„ํ•˜์ง€ ์•Š์ž–์•„์š”? ๋˜‘๊ฐ™์€ ์ฝ”๋“œ๊ฐ€ ๋ฐ˜๋ณต๋˜๋Š”๊ฑฐ ์—ญ์‹œ ์ข‹์•„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ response ๋‚ด์˜ ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜๋Š” ์ฃผ์š” ๊ฒฐ๊ณผ ๋ฐ์ดํ„ฐ๋งŒ ์˜ˆ์˜๊ฒŒ ์ €๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ์ฒ˜๋ฆฌํ•ด ์ฃผ๋„๋ก ํ•˜๋ ค๊ณ  ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
๋ณด๊ธฐ์— ์˜ˆ์˜๊ฒŒ ์ •๋ฆฌํ•˜๋Š” ๊ฒƒ์ด,,,์ €๋Š” ๊ฐœ์ธ์ ์œผ๋กœ ์ข‹์Šต๋‹ˆ๋‹ค.

์‚ฌ์‹ค ์ค‘๋ณต data class๊ฐ€ ๋งŽ์œผ๋ฉด ํ•„์—ฐ์ ์œผ๋กœ ์ฃผ์„์„ ๋งŽ์ด ๋‹ฌ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
๊ทธ๋Ÿฌ๋ฉด ์œ ์ง€๋ณด์ˆ˜ํ•˜๊ธฐ ๋„ˆ๋ฌด ํž˜๋“ค์–ด์„œ์š”. ๊ทธ๋ƒฅ ํ•˜๋‚˜๋กœ ์Œˆ๋นกํ•˜๊ณ  ์˜ˆ์˜๊ฒŒ ์ •๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ๋‚˜์ค‘์—๋„ ์ข‹์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ด ๋ถ€๋ถ„์€ ์ €๋ฒˆ๊ณผ ๋™์ผํ•œ interceptor ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.
์ด ์ฝ”๋“œ ๋‚ด์— ๊ฒฐ๊ณผ ๋ฐ์ดํ„ฐ๋ฅผ ๊ณตํ†ต wrapper response ํด๋ž˜์Šค์— ๋ฌถ๊ณ  ์œ ํšจํ•œ ๋ฐ์ดํ„ฐ๋“ค๋งŒ ๋„˜๊ฒจ์ฃผ๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

interceptor ํด๋ž˜์Šค ๋‚ด์—์„œ, responseBody ๋‚ด๋ถ€ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•˜์—ฌ, responsebody๋ฅผ ์žฌ๊ตฌ์„ฑํ•˜์˜€์Šต๋‹ˆ๋‹ค.
responseWrapper์˜ result๋ฐ์ดํ„ฐ๋ฅผ responsebody ๋ฐ์ดํ„ฐ๋กœ ์น˜ํ™˜ํ•˜๋Š” ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋ฉด ๋กœ๊ทธ ์ƒ์œผ๋กœ๋„ ๋ฐ˜๋ณต์ ์œผ๋กœ ๋‚ด๋ ค์˜ค๋˜ ๋ฐ์ดํ„ฐ๊ฐ€ ์•„๋‹Œ result์˜ ๋ฐ์ดํ„ฐ๊ฐ€ responsebody๋ฐ์ดํ„ฐ๋กœ ๋„˜์–ด์˜ค๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
(์ด ๋ถ€๋ถ„์€ ๋”ฐ๋กœ ์‚ฌ๋‚ด ๋ฐ์ดํ„ฐ ๋กœ๊ทธ์ด๊ธฐ ๋•Œ๋ฌธ์— ๋กœ๊ทธ ์ œ๊ณต์ด ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.)

class NetworkInterceptor: Interceptor {

    private companion object {
        private const val SERVER_ERROR_CODE = 500
    }

    override fun intercept(chain: Interceptor.Chain): Response {

        try {
            val newRequest = chain.request().newBuilder().build()
            val response = chain.proceed(newRequest)

            val rawData = responseBody(response)

            return response.newBuilder()
                .message(response.message)
                .body(rawData?.toResponseBody())
                .build()

        } catch (e: Exception) {
            val message: String = when(e) {
                is SocketTimeoutException -> "SocketTimeoutException"
                else -> "Exception"
            }

            return Response.Builder()
                .request(chain.request())
                .protocol(Protocol.HTTP_2)
                .code(SERVER_ERROR_CODE)
                .message(message)
                .body("{$e}".toResponseBody(null))
                .build()
        }
    }

    private fun responseBody(response: Response): String? {
        val responseBody = response.body ?: return "{}"
        val contentLength = responseBody.contentLength()
        if (contentLength == 0L) {
            return "{}"
        }

        val res = Gson().fromJson<ResponseWrapper<*>>(
            response.body?.string() ?: "{}",
            object : TypeToken<ResponseWrapper<*>>() {}.type
        )

        return if (res.result == null) "{}" else Gson().toJson(res.result)

    }
}

ResponseWrapper ๋‚ด๋ถ€์— ๋ฌถ์ธ code, message, description์€ ๋ชจ๋“  API์—์„œ ๊ณตํ†ต์ ์œผ๋กœ ๋‚ด๋ ค์ฃผ๋Š” ๋ฐ์ดํ„ฐ์ž…๋‹ˆ๋‹ค.
๊ทธ ํ•˜์œ„์— result๊ฐ€ ์‹ค์ œ์ ์œผ๋กœ ํ•„์š”ํ•œ ๊ฒฐ๊ณผ ๋ฐ์ดํ„ฐ์ด์ง€์š”.

์•„๋งˆ ์ด ์ •๋„๊ฐ€ ๊ฐ€์žฅ ๋ฒ ์ด์งํ•œ ๊ตฌ์กฐ์ด๊ณ  ์„œ๋ฒ„ ๊ตฌ์กฐ ๋ฐ ์„œ๋น„์Šค ๊ตฌ์„ฑ์— ๋”ฐ๋ผ ํ† ํฐ์ด ์ด๊ณณ์— ์˜ค๊ณ  ๊ฐˆ ์ˆ˜๋„ ์žˆ๊ฒ ๊ณ 
๋‹ค๋ฅธ ํƒ€์ž… ๋ฐ์ดํ„ฐ๋“ค์ด ๋„˜์–ด์˜ฌ ์ˆ˜๋„ ์žˆ๊ฒ ์Šต๋‹ˆ๋‹ค.

๊ณตํ†ต์ ์œผ๋กœ ์ฒ˜๋ฆฌ๋˜๋Š” ๊ฒƒ๋“ค์€ ResponsoeWrapper๋‚ด์— ๋„ฃ์–ด์„œ ํ•˜๋‚˜๋กœ ๊ด€๋ฆฌ ๋  ์ˆ˜ ์žˆ๋„๋กœ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

@Parcelize
data class ResponseWrapper<T>(

    @SerializedName("code")
    val code: String,
    @SerializedName("message")
    val message: String,
    @SerializedName("description")
    val description: String,

    @SerializedName("result")
    val result: @RawValue T? = null
)

์ด๋Ÿฌ๋ฉด ์ค‘๋ณต์ ์ธ data class๋Š” ํ•˜๋‚˜๋กœ ์ฒ˜๋ฆฌํ•˜๊ณ  ๊ฒฐ๊ณผ ๋ฐ์ดํ„ฐ๋“ค์˜ data class๋งŒ ์ž˜ ๊ด€๋ฆฌํ•ด์„œ ์—ฐ๊ฒฐํ•ด ์ฃผ๋ฉด
๊ทธ๋Ÿญ์ €๋Ÿญ ๊น”๋”ํ•œ ์ฝ”๋“œ ๊ด€๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

728x90
๋ฐ˜์‘ํ˜•