Getting JSON Body from Retrofit Error (Kotlin)

Timi Ajiboye
chunks of code*
Published in
2 min readAug 13, 2017

Update: You can see the class we end up writing, but in Java here.

I started using Kotlin in Android, yesterday. Yes, yesterday. I haven’t even done serious Android development in a while, so I was completely lost; drowning in terms like rxjava, LiveData, MVVM, AAC, Dagger and all the new-ish things that have appeared since I last did battle with Android.

Thanks to Efeturi Money (who I’ve asked about 50 billion questions in the past 24 hours), I’ve started to understand things and drown a lot less.

There’s this specific problem I faced, barely some minutes ago, which one can easily grok from the title. But before we get into how to solve it, I’d like to detail my specific use-case.

I’m trying to make a simple request, with Retrofit to the server and upon getting an error (including any response with status code 400–500), retrieve the error message and maybe display it with a toast or whatever else.

This particular server responds with JSON similar to this in such situations:

// Status code: 400{
"message":"Random Error Message"
}

This sounds simple enough, right? Well, it kind of is, but a little extra effort is needed to do it neatly.

Imagine I’m subscribing to the Retrofit call’s response as such:

...
.subscribe({ randomResponse, error ->
if (error != null) {
// TODO: Retrieve error message
} else {
// TODO: Do other things
}
})

When there is no error, Retrofit works fine, it converts the JSON response body into an object of whatever class you’ve specified (randomResponse).

However, when there’s an error, it doesn’t do that. What it does, is give you error: Throwable!, and as a result, it’s a bit stressful to get the "message" which we know is in our JSON response body.

Efeturi Money discovered that when the status of the response from the server is 400–500, error is actually an HttpException (which is a subclass of Throwable).

So, one can do an if statement, to check if this is the case and act accordingly.

var message = "An error occurred"if (error is HttpException) {
// Kotlin will smart cast at this point
val errorJsonString = error.response().errorBody()?.string()
message = JsonParser().parse(errorJsonString)
.asJsonObject["message"]
.asString
} else {
message = error.message ?: this.message
}

We can get the JSON (as a string) from the HttpException as is done above with error.response().errorBody()?.string() and then parse it however you like. Once parsed, you can get the "message" and display it.

If the error isn’t an HttpException, use the error message instead (or the fallback).

All of this can be put into a class like this:

class ApiError constructor(error: Throwable) {
var message = "An error occurred"

init {
if (error is HttpException) {
val errorJsonString = error.response()
.errorBody()?.string()
this.message = JsonParser().parse(errorJsonString)
.asJsonObject["message"]
.asString
} else {
this.message = error.message ?: this.message
}
}
}

And can be reused neatly everywhere like this:

.subscribe({ randomResponse, error ->
if (error != null) {
val errorMessage = ApiError(error).message
...
} else {
// TODO: Do other things
}
})

That’s all! ✌🏾

--

--

Timi Ajiboye
chunks of code*

I make stuff, mostly things that work on computers. Building Gandalf.