보통 REST API 의 응답 객체는
{
"status" : "success",
"message" : null,
"data" : { data1 }
}
위와 같이 상태, 메세지, 데이터 형식으로 주어지는 것이 일반적이다.
따라서 파라미터 값에 따라 리스폰스 반환 값을 만드는 데 실패하게 되는 경우에도 어쨌거나 '실패'라는 응답을 받게 된다. 그러면 클라이언트 측에서는 해당 리스폰스에 따라 예외처리를 해주면 된다.
그러나!
여러 프로젝트를 진행하다보면 api 응답 형식이 각자 다른 것을 알 수 있다.
나의 경우 이번 프로젝트에서 파라미터 값에 따라 리스폰스가 아예 비어있는 경우가 존재하는 api를 다루게 되었다.
서버 개발자에게 실패의 경우에도 리스폰스를 만들어달라 할 수 있다면 그것이 베스트일테지만, 나는 클라이언트 측에서 response body가 null인 경우에 대응해보고자 노력해보았다.
그리고 혹시 또 나와 같은 상황에 처해있는 사람이 있을 수 있으니 과정과 결과를 공유해보고자 한다.
주어진 상황은 친구를 추가하는 화면에서
api를 연동해야 하는 상황이다.
여기서 만약 고유 코드에 해당하는 유저가 없다면 리스폰스가 비어있어 아래와 같이 'Content-Length 가 0' 이라는 말과 함께 java.io.EOFExption
을 발생시키게 된다.
java.io.EOFExption에 대한 에러코드를 구글링해보니 response body가 비어있는 경우 해당 응답을 null로 변환하는 Retrofit 컨버터를 추가해줄 수 있었다.
Retrofit Github Issue 중에 아래와 같이 컨버터에 대한 코드를 공유해준 유저가 있었고,
더 아래로 내려가다보면 Kotlin 개발자를 위해 Kotlin으로 해당 컨버터 코드를 올려준 사람도 있었다!!!!
그래서 당장 Retrofit 구현체에 이를 아래와 같이 적용시켜 주었는데, 여전히 같은 에러를 만날 수 있었다......
좌절할 뻔 하였으나.. 아래와 같이 nullOnEmptyConverterFactory
컨버터 를 GsonConverterFactory.create(gson)
컨버터보다 먼저 써줘야 하는 문제였다.
private val nullOnEmptyConverterFactory = object : Converter.Factory() {
fun converterFactory() = this
override fun responseBodyConverter(type: Type, annotations: Array<out Annotation>, retrofit: Retrofit) = object : Converter<ResponseBody, Any?> {
val nextResponseBodyConverter = retrofit.nextResponseBodyConverter<Any?>(converterFactory(), type, annotations)
override fun convert(value: ResponseBody) = if (value.contentLength() == 0L) null else nextResponseBodyConverter.convert(value)
}
}
그리고 이제 잘 되나 시도해보았더니...
이제는 다른 에러가 뜨기 시작했다.
response body가 non-null
타입으로 지정되어 있는데 null
response가 들어왔다는 것이다. 보통은 response body가 null
일 일이 없기 때문에 당연히 고려해보지 못한 부분이었다.
그래서 아래와 같이 인터페이스에서 리스폰스 값을 널러블하게 바꿔주었고
리스폰스의 유저 정보를 옵저빙할 때 널값인 경우 검색 결과가 없다는 텍스트를 띄울 수 있도록 아래와 같이 예외처리를 해주었다.
이제 해당 고유코드를 가진 유저가 없는 경우에는 에러 없이 이렇게 잘 작동하는 것을 확인할 수 있다.
결론: nullOnEmptyConverterFactory
컨버터를 추가해주고 해당 리스폰스 바디를 널러블하게 바꿔주면 된다!