[Android] API Response 처리

Sdoubleu·2024년 6월 28일
0

Android

목록 보기
13/16
post-thumbnail

API를 이용할 때, 요청에 대한 응답은 성공이든 실패든 반드시 돌아옵니다
이러한 응답을 보다 명확하게 처리하기 위해, 결과를 세분화하여 처리하는 것이 좋습니다

API 응답을 다룰 때는 응답의 유형을 명확히 구분하고, 각각에 대한 적절한 처리를 설계하는 것이 중요합니다
이는 시스템의 안정성을 높이고, 예기치 않은 상황에 대한 대응력을 강화합니다


API Response Handling

API 호출 후 응답은 크게 두 가지로 나눌 수 있습니다: 성공 응답실패 응답


성공 응답

성공적인 API 호출은 서버가 요청을 정상적으로 처리했음을 의미합니다
일반적으로 성공 응답에는 다음과 같은 요소가 포함됩니다

  • HTTP 상태 코드: 200번대 (예: 200 OK, 201 Created 등)
  • 응답 본문: 요청한 데이터 또는 작업 결과를 포함 (JSON, XML 등)

실패 응답

실패한 API 호출은 여러 가지 원인으로 발생할 수 있으며, 이를 적절히 처리하는 것이 중요합니다
실패 응답에는 다음과 같은 요소가 포함될 수 있습니다

  • HTTP 상태 코드: 400번대 (클라이언트 오류) 또는 500번대 (서버 오류)
  • 오류 메시지: 오류 원인에 대한 설명 또는 코드

실패 응답 처리 시 유의할 점

  1. 오류 유형 구분: 상태 코드와 오류 메시지를 통해 오류의 원인을 파악합니다
  2. 재시도 로직: 특정 조건에 따라 요청을 재시도할 수 있는 로직을 구현합니다
  3. 사용자 피드백: 사용자에게 적절한 오류 메시지와 함께 문제를 알리고, 필요한 조치를 안내합니다
  4. 로깅 및 모니터링: 오류 발생 시 이를 로깅하여 추후 분석하고, 시스템의 안정성을 개선합니다

좋지 못한 예시

class LoginRemoteDataSource @Inject constructor() {
    private val loginApiService = LoginRetrofitClient.loginApi

    suspend fun loginApi(
        provider: String,
        accessToken: LoginRequest,
    ): LoginResponse? {
        try {
            val loginGetResponse = loginApiService.getAccessToken(
                provider,
                accessToken,
            )

            if (loginGetResponse.code() != 200) {
                return null
            }

            return loginGetResponse.body()
        } catch (e: Exception) {
            Log.e("LoginGetException", e.toString())
            return null
        }
    }
}

현재 코드는 API 호출의 응답 코드를 확인하여, 200이 아닌 경우 null을 반환합니다
이는 성공 응답만 처리하고 실패 응답은 무시하는 간단한 로직입니다


개선 사항

API Result 도입

sealed class ApiResult<out T> {
    data class Success<out T>(val data: T) : ApiResult<T>()
    data class Error(val errorCode: String, val description: String) : ApiResult<Nothing>()
    data class Exception(val e: Throwable) : ApiResult<Nothing>()
}
  • API Result 클래스를 도입함으로써 여러 에러 코드를 포함한 응답 상태에 따른 세부적인 분류 및 처리가 가능해졌습니다
viewModelScope.launch {
	val response = profileGetUsecase.invoke()
	when(response) {
		is ApiResult.Error -> {
			val code = response.errorCode
			val responseDsscription = response.description
			when(code) {
				"400" -> ...
				"401" -> ...
				"402" -> ...
				"403" -> ...
				"404" -> ...
				else -> ...
			}
		}
		is ApiResult.Exception -> {
			Log.d(
				"recommended Exception",
				response.e.message ?: "No message available"
			)
		}
		is ApiResult.Success -> {
			setUserInfo(response.data)
		}
	}
}

API Result 도입 후 장점

  • 응답 코드 처리의 세분화
    응답 코드가 200이 아닌 경우 모두 null로 처리하는 것이 아닌,
    다양한 응답 코드를 세분화 하여 별도로 처리하면 사용자에게 더 명확한 피드백을 제공할 수 있습니다

  • 로깅 개선
    현재 예외 발생 시 로그를 출력하고 있지만, 추가적인 정보를 포함하면 로그를 더 상세하게 기록하면 문제를 파악하기 더 용이해집니다

  • 결과 래핑
    좋지 않은 예시에서 사용한 LoginRespose?를 반환하여 성공/실패를 구분했지만, APIResult 클래스와 같은 래퍼 클래스를 사용하여 성공/실패와 함께 관련 메세지나 데이터를 포함하는 방법도 고려 가능해집니다

profile
개발자희망자

0개의 댓글