-
Notifications
You must be signed in to change notification settings - Fork 1
[Refactor/#82] 예외 처리 내부 구조 변경 #83
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,100 @@ | ||
| package com.acon.acon.data.error | ||
|
|
||
| import kotlinx.serialization.json.Json | ||
| import okhttp3.Request | ||
| import okio.Timeout | ||
| import retrofit2.Call | ||
| import retrofit2.CallAdapter | ||
| import retrofit2.Callback | ||
| import retrofit2.Response | ||
| import retrofit2.Retrofit | ||
| import java.lang.reflect.ParameterizedType | ||
| import java.lang.reflect.Type | ||
|
|
||
| class RemoteErrorCallAdapterFactory( | ||
| private val json: Json = Json | ||
| ) : CallAdapter.Factory() { | ||
|
|
||
| override fun get( | ||
| returnType: Type, annotations: Array<Annotation>, retrofit: Retrofit | ||
| ): CallAdapter<Any, Call<Any>>? { | ||
| if (getRawType(returnType) != Call::class.java) return null | ||
|
|
||
| val responseType = (returnType as ParameterizedType).actualTypeArguments[0] | ||
| return RemoteErrorCallAdapter(responseType, json) | ||
| } | ||
|
|
||
| private class RemoteErrorCallAdapter<R>( | ||
| private val responseType: Type, private val json: Json | ||
| ) : CallAdapter<R, Call<R>> { | ||
|
|
||
| override fun responseType(): Type = responseType | ||
|
|
||
| override fun adapt(call: Call<R>): Call<R> { | ||
| return object : Call<R> { | ||
| override fun enqueue(callback: Callback<R>) { | ||
| call.enqueue(object : Callback<R> { | ||
| override fun onResponse(call: Call<R>, response: Response<R>) { | ||
| if (response.isSuccessful) { | ||
| if (response.body() != null) | ||
| callback.onResponse(call, response) | ||
| else { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 여기에서 response의 body가 null이라는 것은 홈 화면의 가게 리스트가 emptyList 이런 것이 아닌 body자체가 null이란 뜻인건가요??
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 네 body가 null이라서 정상적인 상황은 아님을 나타냅니다. |
||
| callback.onFailure( | ||
| call, RemoteError( | ||
| response = response, | ||
| errorCode = 0, | ||
| message = "Empty body", | ||
| ) | ||
| ) | ||
| } | ||
| } else { | ||
| val errJson = response.errorBody()?.string() | ||
| val errResp = try { | ||
| errJson?.let { json.decodeFromString<NetworkErrorResponse>(it) } | ||
| } catch (_: Exception) { | ||
| null | ||
| } | ||
| callback.onFailure( | ||
| call, RemoteError( | ||
| response = response, | ||
| errorCode = errResp?.code ?: 0, | ||
| message = errResp?.message ?: response.message(), | ||
| ) | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| override fun onFailure(call: Call<R>, t: Throwable) { | ||
| callback.onFailure(call, t) | ||
| } | ||
| }) | ||
| } | ||
|
|
||
| override fun execute(): Response<R> { | ||
| val response = call.execute() | ||
| if (response.isSuccessful) return response | ||
| val errJson = response.errorBody()?.string() | ||
| val errResp = try { | ||
| errJson?.let { json.decodeFromString<NetworkErrorResponse>(it) } | ||
| } catch (_: Exception) { | ||
| null | ||
| } | ||
| throw RemoteError( | ||
| response = response, | ||
| errorCode = errResp?.code ?: 0, | ||
| message = errResp?.message ?: response.message(), | ||
| ) | ||
| } | ||
|
|
||
| override fun clone(): Call<R> = adapt(call.clone()) | ||
| override fun isExecuted(): Boolean = call.isExecuted | ||
| override fun cancel() = call.cancel() | ||
| override fun isCanceled(): Boolean = call.isCanceled | ||
| override fun request(): Request = call.request() | ||
| override fun timeout(): Timeout = call.timeout() | ||
|
|
||
|
|
||
| } | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,10 +1,26 @@ | ||
| package com.acon.acon.data.error | ||
|
|
||
| import java.io.IOException | ||
| import retrofit2.HttpException | ||
| import retrofit2.Response | ||
|
|
||
| /** | ||
| * 400, 500번대 에러 발생 시 던져지는 에러 | ||
| */ | ||
| data class RemoteError( | ||
| val statusCode: Int, | ||
| val response: Response<*>, | ||
| val errorCode: Int, | ||
| override val message: String, | ||
| val httpErrorMessage: String | ||
| ) : IOException() | ||
| ) : HttpException(response) { | ||
|
|
||
| val statusCode: Int = response.code() | ||
| val httpErrorMessage: String = mapHttpError(statusCode) | ||
| } | ||
|
|
||
| private fun mapHttpError(code: Int) = when (code) { | ||
| 400 -> "Bad Request: 잘못된 요청입니다." | ||
| 401 -> "Unauthorized: 인증되지 않은 사용자입니다." | ||
| 403 -> "Forbidden: 접근 권한이 없습니다." | ||
| 404 -> "Not Found: 요청한 리소스를 찾을 수 없습니다." | ||
| in 500 until 600 -> "Internal Server Error: 서버 내부 오류입니다." | ||
| else -> "Unknown Error: 알 수 없는 오류입니다." | ||
| } | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이렇게 RemoteError.kt를 사용하는 구조로 변경했을 때 실제 동작에서의 차이도 있을까요??
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 아뇨 차이없습니당. |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
여기서 Call을 사용하신 이유가 궁금합니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
어떤 이유라기 보다는 CallAdapter를 확장할 때, 타입으로 원래 Call를 지정해주어야 하는 것으로 알고 있습니다.