From 6712912ddece8363b3960a4e5e407bd5edf8a9ea Mon Sep 17 00:00:00 2001 From: Kimchohee Date: Thu, 28 Apr 2022 21:34:13 +0900 Subject: [PATCH] =?UTF-8?q?[#17]=20=ED=86=B5=EC=8B=A0=EC=9D=84=20=EC=9C=84?= =?UTF-8?q?=ED=95=9C=20=EB=84=A4=ED=8A=B8=EC=9B=8C=ED=81=AC=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=EB=B2=A0=EC=9D=B4=EC=8A=A4=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1=20-=20=EB=A6=AC=EB=B7=B0=20=EB=B0=98?= =?UTF-8?q?=EC=98=81=20-=20=EB=A0=88=ED=8A=B8=EB=A1=9C=ED=95=8F=20?= =?UTF-8?q?=EB=B2=84=EC=A0=84=20=EB=B3=80=EC=88=98=20=EC=A0=95=EC=9D=98=20?= =?UTF-8?q?-=20Failure=20=EC=8B=9C=20Throwable=EB=A1=9C=20=EB=8B=A4?= =?UTF-8?q?=EB=A3=A8=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD=20-=20request?= =?UTF-8?q?=20url=20=EA=B8=B0=EB=A1=9D=20-=20Exception=20=EA=B5=AC?= =?UTF-8?q?=EC=A1=B0=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 5 +- .../moyerun/moyeorun_android/MainActivity.kt | 15 +++- .../common/exceptions/ApiException.kt | 11 +++ .../common/exceptions/NetworkException.kt | 7 ++ .../network/api/ApiErrorCase.kt | 22 ++++++ .../network/api/ApiService.kt | 2 +- .../network/calladapter/ApiResult.kt | 6 +- .../network/calladapter/ApiResultCall.kt | 79 +++++++++++-------- .../calladapter/ApiResultCallAdapter.kt | 2 +- .../ApiResultCallAdapterFactory.kt | 2 +- .../network/client/Retrofit.kt | 2 +- 11 files changed, 106 insertions(+), 47 deletions(-) create mode 100644 app/src/main/java/com/moyerun/moyeorun_android/common/exceptions/ApiException.kt create mode 100644 app/src/main/java/com/moyerun/moyeorun_android/common/exceptions/NetworkException.kt create mode 100644 app/src/main/java/com/moyerun/moyeorun_android/network/api/ApiErrorCase.kt diff --git a/app/build.gradle b/app/build.gradle index da8b9b2..15777bd 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -68,6 +68,7 @@ android { dependencies { def glide_version = '4.13.1' + def retrofit_version = '2.9.0' implementation 'androidx.core:core-ktx:1.7.0' implementation 'androidx.appcompat:appcompat:1.4.1' @@ -91,8 +92,8 @@ dependencies { annotationProcessor "com.github.bumptech.glide:compiler:$glide_version" // Retrofit2 - implementation 'com.squareup.retrofit2:retrofit:2.9.0' - implementation 'com.squareup.retrofit2:converter-gson:2.9.0' + implementation "com.squareup.retrofit2:retrofit:$retrofit_version" + implementation "com.squareup.retrofit2:converter-gson:$retrofit_version" // Coroutine implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0' diff --git a/app/src/main/java/com/moyerun/moyeorun_android/MainActivity.kt b/app/src/main/java/com/moyerun/moyeorun_android/MainActivity.kt index a971161..f36bcfe 100644 --- a/app/src/main/java/com/moyerun/moyeorun_android/MainActivity.kt +++ b/app/src/main/java/com/moyerun/moyeorun_android/MainActivity.kt @@ -3,7 +3,8 @@ package com.moyerun.moyeorun_android import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import com.moyerun.moyeorun_android.common.Lg -import com.moyerun.moyeorun_android.network.callAdapter.ApiResult +import com.moyerun.moyeorun_android.common.exceptions.ApiException +import com.moyerun.moyeorun_android.network.calladapter.ApiResult import com.moyerun.moyeorun_android.network.client.apiService import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch @@ -25,7 +26,11 @@ class MainActivity : AppCompatActivity() { Lg.d("postman test Success response 2 ${response1.body.data}") } is ApiResult.Failure -> { - Lg.d("postman test Failure response 2 ${response1.errorBody.message}") + when (response1.exception) { + is ApiException -> { + Lg.d("postman test Failure response 2 ${response1.exception.message}") + } + } } } when (response2) { @@ -33,7 +38,11 @@ class MainActivity : AppCompatActivity() { Lg.d("postman test Success response 3 ${response2.body.data}") } is ApiResult.Failure -> { - Lg.d("postman test Failure response 3 ${response2.errorBody.message}") + when (response2.exception) { + is ApiException -> { + Lg.d("postman test Failure response 2 ${response2.exception.message}") + } + } } } } diff --git a/app/src/main/java/com/moyerun/moyeorun_android/common/exceptions/ApiException.kt b/app/src/main/java/com/moyerun/moyeorun_android/common/exceptions/ApiException.kt new file mode 100644 index 0000000..75c2ab2 --- /dev/null +++ b/app/src/main/java/com/moyerun/moyeorun_android/common/exceptions/ApiException.kt @@ -0,0 +1,11 @@ +package com.moyerun.moyeorun_android.common.exceptions + +import com.moyerun.moyeorun_android.network.api.Error + +class ApiException(val url: String, val error: Error) : RuntimeException() { + val case: String + get() = error.case + + override val message: String? + get() = error.message +} \ No newline at end of file diff --git a/app/src/main/java/com/moyerun/moyeorun_android/common/exceptions/NetworkException.kt b/app/src/main/java/com/moyerun/moyeorun_android/common/exceptions/NetworkException.kt new file mode 100644 index 0000000..7155295 --- /dev/null +++ b/app/src/main/java/com/moyerun/moyeorun_android/common/exceptions/NetworkException.kt @@ -0,0 +1,7 @@ +package com.moyerun.moyeorun_android.common.exceptions + +import java.lang.RuntimeException + +class NetworkException(message: String, cause: Throwable) : RuntimeException(message, cause) { + +} \ No newline at end of file diff --git a/app/src/main/java/com/moyerun/moyeorun_android/network/api/ApiErrorCase.kt b/app/src/main/java/com/moyerun/moyeorun_android/network/api/ApiErrorCase.kt new file mode 100644 index 0000000..abba91d --- /dev/null +++ b/app/src/main/java/com/moyerun/moyeorun_android/network/api/ApiErrorCase.kt @@ -0,0 +1,22 @@ +package com.moyerun.moyeorun_android.network.api + +import com.moyerun.moyeorun_android.common.exceptions.ApiException + +enum class ApiErrorCase(val case: String) { + // 서버와 합의된 에러 케이스들을 정의합니다. + NOT_LOGIN("100"), // TODO : 예시입니다. 실제 로그인 작업 시 수정해주세요. + UNKNOWN("999"); + + companion object { + private fun findError(case: String): ApiErrorCase { + return values().find { it.case == case } ?: UNKNOWN + } + + fun getException(url: String, error: Error, cause: Throwable? = null): Throwable { + return when(findError(error.case)) { + NOT_LOGIN -> { TODO() } + else -> ApiException(url, error) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/moyerun/moyeorun_android/network/api/ApiService.kt b/app/src/main/java/com/moyerun/moyeorun_android/network/api/ApiService.kt index c842265..48699cb 100644 --- a/app/src/main/java/com/moyerun/moyeorun_android/network/api/ApiService.kt +++ b/app/src/main/java/com/moyerun/moyeorun_android/network/api/ApiService.kt @@ -1,6 +1,6 @@ package com.moyerun.moyeorun_android.network.api -import com.moyerun.moyeorun_android.network.callAdapter.ApiResult +import com.moyerun.moyeorun_android.network.calladapter.ApiResult import retrofit2.http.GET interface ApiService { diff --git a/app/src/main/java/com/moyerun/moyeorun_android/network/calladapter/ApiResult.kt b/app/src/main/java/com/moyerun/moyeorun_android/network/calladapter/ApiResult.kt index cf13bcf..0d13ac9 100644 --- a/app/src/main/java/com/moyerun/moyeorun_android/network/calladapter/ApiResult.kt +++ b/app/src/main/java/com/moyerun/moyeorun_android/network/calladapter/ApiResult.kt @@ -1,6 +1,4 @@ -package com.moyerun.moyeorun_android.network.callAdapter - -import com.moyerun.moyeorun_android.network.api.Error +package com.moyerun.moyeorun_android.network.calladapter /** * Success : API 호출 성공 시, body를 Wrapping 합니다. @@ -8,5 +6,5 @@ import com.moyerun.moyeorun_android.network.api.Error */ sealed class ApiResult { data class Success(val body: T) : ApiResult() - data class Failure(val errorBody: Error) : ApiResult() + data class Failure(val exception: Throwable) : ApiResult() } \ No newline at end of file diff --git a/app/src/main/java/com/moyerun/moyeorun_android/network/calladapter/ApiResultCall.kt b/app/src/main/java/com/moyerun/moyeorun_android/network/calladapter/ApiResultCall.kt index e968276..a53f34f 100644 --- a/app/src/main/java/com/moyerun/moyeorun_android/network/calladapter/ApiResultCall.kt +++ b/app/src/main/java/com/moyerun/moyeorun_android/network/calladapter/ApiResultCall.kt @@ -1,12 +1,12 @@ -package com.moyerun.moyeorun_android.network.callAdapter +package com.moyerun.moyeorun_android.network.calladapter +import com.google.gson.Gson +import com.moyerun.moyeorun_android.common.exceptions.NetworkException +import com.moyerun.moyeorun_android.network.api.ApiErrorCase import com.moyerun.moyeorun_android.network.api.Error -import com.moyerun.moyeorun_android.network.client.retrofit import okhttp3.Request -import okhttp3.ResponseBody import okio.Timeout import retrofit2.* -import java.io.IOException class ApiResultCall( private val delegate: Call @@ -14,6 +14,8 @@ class ApiResultCall( override fun enqueue(callback: Callback>) { delegate.enqueue(object : Callback { override fun onResponse(call: Call, response: Response) { + val requestUrl = delegate.request().url().toString() + // status code 200번대. if (response.isSuccessful) { val body = response.body() @@ -23,47 +25,62 @@ class ApiResultCall( Response.success(ApiResult.Success(body)) ) } else { - val message = "response body is null." - val case = "001" // TODO : 바디가 null일 경우 합의된 케이스 번호로 변경 필요함. 001은 임시 번호임. callback.onResponse( this@ApiResultCall, - Response.success(ApiResult.Failure(Error(message, case))) + Response.success( + ApiResult.Failure( + NetworkException( + "Response from $requestUrl was null " + + "but response body type was decleared as non-null", + HttpException(response) + ) + ) + ) ) } - } else { // status code 200 아닌 다른 것들. - val errorBody = response.errorBody()?.let { getErrorResponse(it) } + } else { // status code 200번대 아님. + val errorBody = response.errorBody() if (errorBody != null) { + val errorResponse = Gson().fromJson(errorBody.string(), Error::class.java) callback.onResponse( this@ApiResultCall, - Response.success(ApiResult.Failure(errorBody)) + Response.success( + ApiResult.Failure( + ApiErrorCase.getException( + requestUrl, + errorResponse, + HttpException(response) + ) + ) + ) ) } else { - val message = "error body is null." - val case = "002" // TODO : 에러 바디가 null일 경우 합의된 케이스 번호로 변경 필요함. 002은 임시 번호임. callback.onResponse( this@ApiResultCall, - Response.success(ApiResult.Failure(Error(message, case))) + Response.success( + ApiResult.Failure( + NetworkException( + requestUrl, + HttpException(response) + ) + ) + ) ) } } } - override fun onFailure(call: Call, t: Throwable) { - val networkResponse = when (t) { - is IOException -> { - val message = "network error occurred." - val case = "003" // TODO : 네트워크 에러 발생 시 합의된 케이스 번호로 변경 필요함. 003은 임시 번호임. - Error(message, case) - } - else -> { - val message = "unknown error occurred." - val case = "004" // TODO : 언논 에러 발생 시 합의된 케이스 번호로 변경 필요함. 004는 임시 번호임. - Error(message, case) - } - } + override fun onFailure(call: Call, throwable: Throwable) { callback.onResponse( this@ApiResultCall, - Response.success(ApiResult.Failure(networkResponse)) + Response.success( + ApiResult.Failure( + NetworkException( + call.request().url().toString(), + throwable + ) + ) + ) ) } }) @@ -72,7 +89,7 @@ class ApiResultCall( override fun clone(): Call> = ApiResultCall(delegate.clone()) override fun execute(): Response> { - throw UnsupportedOperationException("NetworkResponseCall doesn't support execute") + throw UnsupportedOperationException("ApiResultCall doesn't support execute") } override fun isExecuted(): Boolean = delegate.isExecuted @@ -87,10 +104,4 @@ class ApiResultCall( override fun timeout(): Timeout = delegate.timeout() - private fun getErrorResponse(errorBody: ResponseBody): Error? { - return retrofit.responseBodyConverter( - Error::class.java, - Error::class.java.annotations - ).convert(errorBody) - } } \ No newline at end of file diff --git a/app/src/main/java/com/moyerun/moyeorun_android/network/calladapter/ApiResultCallAdapter.kt b/app/src/main/java/com/moyerun/moyeorun_android/network/calladapter/ApiResultCallAdapter.kt index a336916..3924227 100644 --- a/app/src/main/java/com/moyerun/moyeorun_android/network/calladapter/ApiResultCallAdapter.kt +++ b/app/src/main/java/com/moyerun/moyeorun_android/network/calladapter/ApiResultCallAdapter.kt @@ -1,4 +1,4 @@ -package com.moyerun.moyeorun_android.network.callAdapter +package com.moyerun.moyeorun_android.network.calladapter import retrofit2.Call import retrofit2.CallAdapter diff --git a/app/src/main/java/com/moyerun/moyeorun_android/network/calladapter/ApiResultCallAdapterFactory.kt b/app/src/main/java/com/moyerun/moyeorun_android/network/calladapter/ApiResultCallAdapterFactory.kt index fa6c44b..081174c 100644 --- a/app/src/main/java/com/moyerun/moyeorun_android/network/calladapter/ApiResultCallAdapterFactory.kt +++ b/app/src/main/java/com/moyerun/moyeorun_android/network/calladapter/ApiResultCallAdapterFactory.kt @@ -1,4 +1,4 @@ -package com.moyerun.moyeorun_android.network.callAdapter +package com.moyerun.moyeorun_android.network.calladapter import retrofit2.Call import retrofit2.CallAdapter diff --git a/app/src/main/java/com/moyerun/moyeorun_android/network/client/Retrofit.kt b/app/src/main/java/com/moyerun/moyeorun_android/network/client/Retrofit.kt index 997fff9..2973e24 100644 --- a/app/src/main/java/com/moyerun/moyeorun_android/network/client/Retrofit.kt +++ b/app/src/main/java/com/moyerun/moyeorun_android/network/client/Retrofit.kt @@ -1,6 +1,6 @@ package com.moyerun.moyeorun_android.network.client -import com.moyerun.moyeorun_android.network.callAdapter.ApiResultCallAdapterFactory +import com.moyerun.moyeorun_android.network.calladapter.ApiResultCallAdapterFactory import com.moyerun.moyeorun_android.network.api.ApiService import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory