Returning error from OKHttp interceptor (using retrofit) Returning error from OKHttp interceptor (using retrofit) android android

Returning error from OKHttp interceptor (using retrofit)


Just had the same scenario and this post helped me implementing the solution. Thanks to @mastov to point to the right direction.

Working with a back-end api that always returns HTTP 200 even if there was an error. This was my response sample of an error

{"status":403,"message":"Bad User credentials","time":1495597740061,"version":"1.0"}

Here is a simple implementation to complement this answer.

public Response intercept(Chain chain) throws IOException {        Request request   = chain.request();        Response response = chain.proceed(request);        ResponseBody body = response.body();        // Only intercept JSON type responses and ignore the rest.        if (body != null && body.contentType() != null && body.contentType().subtype() != null && body.contentType().subtype().toLowerCase().equals("json")) {            String errorMessage = "";            int errorCode       = 200; // Assume default OK            try {                BufferedSource source = body.source();                source.request(Long.MAX_VALUE); // Buffer the entire body.                Buffer buffer   = source.buffer();                Charset charset = body.contentType().charset(Charset.forName("UTF-8"));                // Clone the existing buffer is they can only read once so we still want to pass the original one to the chain.                String json     = buffer.clone().readString(charset);                JsonElement obj = new JsonParser().parse(json);                // Capture error code an message.                if (obj instanceof JsonObject && ((JsonObject) obj).has("status")) {                    errorCode   = ((JsonObject) obj).get("status").getAsInt();                }                if (obj instanceof JsonObject && ((JsonObject) obj).has("message")) {                    errorMessage= ((JsonObject) obj).get("message").getAsString();                }            } catch (Exception e) {                Log.e(TAG, "Error: " + e.getMessage());            }            // Check if status has an error code then throw and exception so retrofit can trigger the onFailure callback method.            // Anything above 400 is treated as a server error.            if(errorCode > 399){                throw new Exception("Server error code: " + errorCode + " with error message: " + errorMessage);            }        }        return response;    }


My solution taken from okhttp3.logging.HttpLoggingInterceptor

class ErrorResponseInterceptor : Interceptor {    override fun intercept(chain: Interceptor.Chain): Response {        val response = chain.proceed(chain.request())        val code = response.code()        if (code in 400..500) {            responseBody(response)?.also { errorString ->                // error string here is a body of server error            }        }        return response    }    private fun responseBody(response: Response): String? {        val responseBody = response.body() ?: return null        val contentLength = responseBody.contentLength()        if (contentLength == 0L) {            return null        }        val source = responseBody.source()        source.request(Long.MAX_VALUE) // Buffer the entire body.        var buffer = source.buffer()        val headers = response.headers()        if ("gzip".equals(headers.get("Content-Encoding"), ignoreCase = true)) {            var gzippedResponseBody: GzipSource? = null            try {                gzippedResponseBody = GzipSource(buffer.clone())                buffer = okio.Buffer()                buffer.writeAll(gzippedResponseBody)            } finally {                gzippedResponseBody?.close()            }        }        val charset: Charset = responseBody.contentType()?.charset(UTF8) ?: UTF8        return buffer.clone().readString(charset)    }    private companion object {        val UTF8: Charset = Charset.forName("UTF-8")    }}


You should throw IOException. In this case retrofit2 will use onFailure path.