본문 바로가기
Projects/FineByMe

[Android/Kotlin] Retrofit 에러 처리 방법: HttpException을 활용한 상태 코드별 에러 메시지 처리

by quessr 2024. 7. 8.

최근 프로젝트에서 Unsplash API를 사용하면서 발생한 에러를 상태 코드별로 처리하는 방법을 공유하고자 합니다. 이 과정에서 Retrofit을 활용하여 서버 응답을 효율적으로 처리할 수 있는 방법을 알게 되었습니다. 특히, HttpException을 활용하여 상태 코드별로 에러 메시지를 처리하는 방법에 대해 자세히 설명드리겠습니다.

문제 상황

처음에는 Unsplash API를 호출할 때 잘못된 API 키를 사용하여 401 Unauthorized 에러를 발생시키고 이를 처리하고자 했습니다. 하지만 예상과 달리 onFailure 콜백이 호출되지 않았습니다. 이에 대해 원인을 분석하고 해결하는 과정을 통해 Retrofit의 에러 처리 방식을 이해하게 되었습니다.

기존 코드

먼저, 기존에 사용하던 NetworkUtils의 enqueueCall 메서드는 다음과 같았습니다.

object NetworkUtils {
    fun <T> enqueueCall(call: Call<T>, onSuccess: (Response<T>) -> Unit, onFailure: (Throwable) -> Unit) {
        call.enqueue(object : Callback<T> {
            override fun onResponse(call: Call<T>, response: Response<T>) {
                if (response.isSuccessful) {
                    onSuccess(response)
                } else {
                    Log.e("NetworkUtils", "Error: ${response.errorBody()?.string()}")
                }
            }

            override fun onFailure(call: Call<T>, t: Throwable) {
                onFailure(t)
            }
        })
    }
}

 

이 코드에서는 서버 응답이 성공적이지 않은 경우에도 onFailure 콜백이 호출되지 않았습니다. 따라서, 서버 응답이 실패한 경우를 적절히 처리할 수 없었습니다.

 

해결 방법

서버 응답이 성공적이지 않을 때, 즉 HTTP 응답 코드가 4xx 또는 5xx인 경우 HttpException을 생성하여 onFailure 콜백을 호출하도록 코드를 수정했습니다. 이를 통해 HttpException으로 서버 응답의 실패를 처리할 수 있게 되었습니다.

 

object NetworkUtils {
    fun <T> enqueueCall(call: Call<T>, onSuccess: (Response<T>) -> Unit, onFailure: (Throwable) -> Unit) {
        call.enqueue(object : Callback<T> {
            override fun onResponse(call: Call<T>, response: Response<T>) {
                if (response.isSuccessful) {
                    onSuccess(response)
                } else {
                    val httpException = HttpException(response)
                    Log.e("NetworkUtils", "Error: ${httpException.message()}")
                    onFailure(httpException)  // HttpException을 onFailure로 전달
                }
            }

            override fun onFailure(call: Call<T>, t: Throwable) {
                // 네트워크 문제 또는 요청 중 예외 발생
                onFailure(t)
            }
        })
    }
}

 

이제 onResponse 메서드에서 서버 응답이 실패한 경우 HttpException을 생성하고 이를 onFailure 콜백으로 전달하게 됩니다. 이를 통해 HttpException을 이용하여 상태 코드별로 에러 메시지를 처리할 수 있습니다.

ViewModel에서 에러 처리

ViewModel에서 HttpException을 처리하여 상태 코드별로 사용자에게 적절한 메시지를 보여줄 수 있습니다. 다음은 PhotoListViewModel의 handleFailure 메서드를 수정한 예시입니다.

 

    private fun handleFailure(throwable: Throwable) {
        val message = when (throwable) {
            is IOException -> {
                Log.e("PhotoListViewModel", "Network error: ${throwable.message}")
                // Show network error message
                ErrorType.NETWORK_ERROR.message
            }

            is retrofit2.HttpException -> {
                val message = when (throwable.code()) {
                    400 -> ErrorType.BAD_REQUEST.message
                    401 -> ErrorType.UNAUTHORIZED.message
                    403 -> ErrorType.FORBIDDEN.message
                    404 -> ErrorType.NOT_FOUND.message
                    500, 503 -> ErrorType.SERVER_ERROR.message
                    else -> "HTTP error: ${throwable.message()}"
                }
                Log.e("PhotoListViewModel", "HTTP error: ${throwable.message}")
                message
            }

            is UnknownHostException -> {
                Log.e("PhotoListViewModel", "No internet connection: ${throwable.message}")
                // Show no internet connection message
                ErrorType.NO_INTERNET.message
            }

            else -> {
                Log.e("PhotoListViewModel", "Unknown error: ${throwable.message}")
                // Show generic error message
                ErrorType.UNKNOWN_ERROR.message
            }
        }
        _errorMassage.postValue(message)

결론

이번 작업을 통해 서버 응답이 성공적이지 않을 때 HttpException을 생성하여 onFailure 콜백으로 전달함으로써, 상태 코드별로 에러 메시지를 처리할 수 있게 되었습니다. 이를 통해 사용자가 보다 명확한 에러 메시지를 받을 수 있게 되었고, 디버깅과 문제 해결이 용이해졌습니다.

 


https://github.com/quessr/fine-by-me 

 

GitHub - quessr/fine-by-me: - 사용자가 즐겨찾기한 사진을 저장하고 관리할 수 있는 안드로이드 애플리

- 사용자가 즐겨찾기한 사진을 저장하고 관리할 수 있는 안드로이드 애플리케이션. Contribute to quessr/fine-by-me development by creating an account on GitHub.

github.com

https://unsplash.com/documentation#error-messages 

 

Unsplash API Documentation | Free HD Photo API | Unsplash

Getting started This document describes the resources that make up the official Unsplash JSON API. If you have any problems or requests, please contact our API team. Creating a developer account To access the Unsplash API, first join. Registering your appl

unsplash.com