Search code examples
androidretrofit2

How to handle errors dynamically in Retrofit


In my application I used Retrofit library for connect to server and some time show me error for validation or other reasons ...
Error message format has such as below:

{
  "message": "The given data was invalid.",
  "errors": {
    "login": [
      "Email or phone is not valid"
    ]
  }
}

login object is change in other API and perhaps show password, basket or other...
I Know I can create error class with above Json and with Gson library convert errorBody and show it!
But I don't want to create a new class for each API !
I want create one general class and get all of errors messages from errors field of Json and show it to user!

My NetworkResponse class:

open class NetworkResponse<T>(private val response: Response<T>) {

    fun generalNetworkResponse(): NetworkRequest<T> {
        return when {
            response.code() == 401 -> NetworkRequest.Error("You are not authorized")
            response.code() == 422 -> NetworkRequest.Error("Api key not found!")
            response.code() == 500 -> NetworkRequest.Error("Try again")
            response.isSuccessful -> NetworkRequest.Success(response.body()!!)
            else -> NetworkRequest.Error(response.message())
        }
    }
}

How can I handle dynamically errors with Retrofit?


Solution

  • Create a class named ApiError

    data class ApiError(
        val message: String?,
        val errors: Map<String, List<String>>?
    )
    

    In your Retrofit Callback implementation, you can use the Gson library to parse the error response into an instance of ApiError. Here's an example:

    
    class MyCallback : Callback<MyResponse> {
    
        override fun onResponse(call: Call<MyResponse>, response: Response<MyResponse>) {
            // handle success response...
        }
    
        override fun onFailure(call: Call<MyResponse>, t: Throwable) {
            // handle network error...
        }
    
        override fun onFailure(call: Call<MyResponse>, response: Response<MyResponse>) {
            if (response.errorBody() != null) {
                try {
                    val apiError = Gson().fromJson(response.errorBody()!!.string(), ApiError::class.java)
                    // handle API error...
                    val errorMessage = apiError.message
                    val errors = apiError.errors
                    // You can iterate through the map of errors and display them to the user
                    errors?.forEach { (field, fieldErrors) ->
                        // display field errors to user
                    }
                } catch (e: IOException) {
                    // handle parsing error...
                }
            } else {
                // handle unexpected error...
            }
        }
    }