Retrofit을 사용하는 인터페이스가 Response와 같이 쉽게 타입체크가 가능한 공통된 타입을 리턴한다면 가능할 수도 있지만, 아니라면 interceptor는 적절한 옵션이 아닐 것 같습니다.
제가 님의 코드를 알 수는 없기 때문에, 정확한 방향은 제시를 못해 드릴 것 같고 한두가지 아이디어를 드리자면,
Retrofit을 바로 쓰지말고 이걸 같은 함수이름을 가진 똑같은 클래스로 감싸서 사용하면 어떨까 싶네요. 에를 들면,
아래처럼, RetrofitApi가 있다고 하죠. (어노테이션 생략)
먼저, 해당 인터페이스의 이름을 바꾸고 접근자도 패키지 레벨로 만들어서 컴파일 에러가 나게 만듧니다.
internal interface AuthApiEx {
suspend fun login(): LoginResult
suspend fun logout(): LogoutResult
}
같은 패키지에 AuthApi 클래스를 똑같은 함수를 가지도록 만듧니다. 이 클래스에 AuthApiEx를 주입합니다.
class AuthApi(
private val deleagate: AuthApiEx
) {
suspend fun login(): LoginResult {
try {
deleagate.login()
} catch(e: Exception) {
}
}
suspend fun logout(): LogoutResult {
try {
deleagate.logout()
} catch(e: Exception) {
}
}
}
이렇게 하면, 아마도 기존 AuthApi를 사용하는 곳에서 코드 교체없이 기존 함수들을 그대로 사용할 수 있지 않을까 생각합니다.
다른 방법으로는 Kotlin extension function을 이용해서, AuthApi의 함수이름을 바꾼 다음, 기존의 함수와 동일한 이름으로 확장함수를 만들어 사용하는 겁니다. 이 경우는 해당 함수들을 사용한 곳에서 import 만 다시 해주면 될 겁니다.
interface AuthApi {
suspend fun loginEx(): LoginResult
suspend fun logoutEx(): LogoutResult
}
fun AuthApi.login(): LoginResult {
try {
this.loginEx()
} catch (e: Exception) {
}
}
fun AuthApi.logout(): LoginResult {
try {
this.logoutEx()
} catch (e: Exception) {
}
}
일단 생각나는 추가적인 옵션은 위의 두가지인데, 님의 코드 상황에 맞게 선택을 하셔야 겠죠. 그리고 인터넷 커넥션의 경우는 API 호출 전에 상태를 체크해서 연결이 끊긴 경우는 API를 호출하지 않고 에러처리를 해주면 더 좋겠죠.
class AuthDelegate(
private val authApi: AuthApi,
private val connectivityChecker: ConnectivityChecker
) {
suspend fun login(): LoginResult {
if (connectivityChecker.isNotConnected()) {
return ...
}
try {
authApi.login()
} catch(e: Exception) {
}
}
...
}
그리고 Kotlin Coroutine을 사용할 때 한가지 팁은 Exception을 리턴하지 말고 Exception의 상태를 리턴하시는게 코루틴의 에러핸들링의 함정을 피할 수 있어 정신건강에 좋다는 겁니다.
sealed class LoginResult {
data class Error(val exception: Exception): LoginResult()
data class Success(val data: LoginInfo): LoginResult()
}
만약 새로운 코드나 함수를 만드실 경우라면, 모든 걸 수동으로 하지마시고 Android Studio 의 코드 템플릿 같은 기능을 이용하셔서 기본적인 코드는 자동생성 하도록 하시면 시간이 많이 절약될 겁니다.