ebeninki
ebeninki

Reputation: 989

Handling Errror Response with Moshi

in my Android app, after sending some registration credentials I get the following JSON output from the server:

{
"response":"successfully registered new user",
"email":"[email protected]",
"username":"testing",
"id":9,
"token":"98d26160e624a0b762ccec0cb561df3aeb131ff5"
}

I have modeled this using the Moshi library with the following data class:

@JsonClass(generateAdapter = true)
data class Account (
    @Json(name = "id")
    val account_id : Long,
    @Json(name="email")
    val account_email: String,
    @Json(name="username")
    val account_username: String,
    @Json(name="token")
    val account_authtoken : String,
    @Json(name="response")
    val account_response : String
)

Everything works fine. Now I wanted to handle error cases. When I get an error (let's say, the email I want to register with already exists) then I should get a JSON output like this:

// what the app gets when there is some error with the credentials
// e.g. email exists, username exists etc.  
{ 
"error_message" : "The email already exists", 
"response": "Error"
}

The method that executes the request looks like the following:

override suspend fun register(email: String, userName: String, password: String, passwordToConfirm: String): NetworkResult<Account> {
        // make the request
        val response = authApi.register(email, userName, password, passwordToConfirm)

        // check if response is successful
        return if(response.isSuccessful){
            try {
                // wrap the response into NetworkResult.Success
                // response.body() contains the Account information
                NetworkResult.Success(response.body()!!)
            }
            catch (e: Exception){
                NetworkResult.Error(IOException("Error occurred during registration!"))
            }
        } else {
            NetworkResult.Error(IOException("Error occurred during registration!"))
        }
    }

If the response is successful, then it wraps the response.body() into NetworkResult.Success data class. My NetworkResult class is a sealed class with two sub data classes Success & Error. It looks like this:

// I get the idea for this from https://phauer.com/2019/sealed-classes-exceptions-kotlin/
sealed class NetworkResult<out R> {
    data class Success<out T>(val data: T) : NetworkResult<T>()
    data class Error(val exception: Exception) : NetworkResult<Nothing>() 
}

But that does not handle the JSON output for errors I mentioned above. When the app gets the error JSON output, Moshi complains that the Account data class does not have a error_message property which is clear to me because I do not have such a field in my Account data class.

What do I need to change so that I can also handle any error cases I wish ? I know, I could model a second data class and call it Error with the fields response and error_message but my sealed class NetworkResult only accepts one class as generic type.

So, what can I do ?

Upvotes: 3

Views: 1420

Answers (1)

Mayur Dhanrajani
Mayur Dhanrajani

Reputation: 72

If you don't initialise a value to a field in data class, Moshi will consider it as a required field.

@JsonClass(generateAdapter = true)
data class Account (
    @Json(name = "id")
    val account_id : Long = 0,
    @Json(name="email")
    val account_email: String = "",
    @Json(name="username")
    val account_username: String = "",
    @Json(name="token")
    val account_authtoken : String = "",
    @Json(name="response")
    val account_response : String = "",
    @Json(name="error_message")
    val error_message : String = ""
)

Like this you can create the same data class for Success and Error both.

Upvotes: 0

Related Questions