diff --git a/src/main/java/io/ipinfo/api/errors/ErrorResponseException.java b/src/main/java/io/ipinfo/api/errors/ErrorResponseException.java index 33155e1..aaa4fc2 100644 --- a/src/main/java/io/ipinfo/api/errors/ErrorResponseException.java +++ b/src/main/java/io/ipinfo/api/errors/ErrorResponseException.java @@ -1,9 +1,29 @@ package io.ipinfo.api.errors; public class ErrorResponseException extends RuntimeException { - public ErrorResponseException() {} + + private final int statusCode; + + public ErrorResponseException() { + this.statusCode = -1; + } public ErrorResponseException(Exception ex) { super(ex); + this.statusCode = -1; + } + + public ErrorResponseException(int statusCode, String responseBody) { + super( + "Unexpected API response (status " + + statusCode + + "): " + + responseBody + ); + this.statusCode = statusCode; + } + + public int getStatusCode() { + return statusCode; } } diff --git a/src/main/java/io/ipinfo/api/request/BaseRequest.java b/src/main/java/io/ipinfo/api/request/BaseRequest.java index 24ce203..cbb86a4 100644 --- a/src/main/java/io/ipinfo/api/request/BaseRequest.java +++ b/src/main/java/io/ipinfo/api/request/BaseRequest.java @@ -9,7 +9,8 @@ import okhttp3.Response; public abstract class BaseRequest { - protected final static Gson gson = new Gson(); + + protected static final Gson gson = new Gson(); private final OkHttpClient client; private final String token; @@ -20,11 +21,12 @@ protected BaseRequest(OkHttpClient client, String token) { public abstract T handle() throws RateLimitedException; - public Response handleRequest(Request.Builder request) throws RateLimitedException { + public Response handleRequest(Request.Builder request) + throws RateLimitedException { request - .addHeader("Authorization", Credentials.basic(token, "")) - .addHeader("user-agent", "IPinfoClient/Java/3.3.0") - .addHeader("Content-Type", "application/json"); + .addHeader("Authorization", Credentials.basic(token, "")) + .addHeader("user-agent", "IPinfoClient/Java/3.3.0") + .addHeader("Content-Type", "application/json"); Response response; @@ -43,7 +45,16 @@ public Response handleRequest(Request.Builder request) throws RateLimitedExcepti throw new RateLimitedException(); } + if (!response.isSuccessful()) { + String body = ""; + try { + if (response.body() != null) { + body = response.body().string(); + } + } catch (Exception ignored) {} + throw new ErrorResponseException(response.code(), body); + } + return response; } } - diff --git a/src/test/java/io/ipinfo/IPinfoTest.java b/src/test/java/io/ipinfo/IPinfoTest.java index 7435c73..7a8b759 100644 --- a/src/test/java/io/ipinfo/IPinfoTest.java +++ b/src/test/java/io/ipinfo/IPinfoTest.java @@ -1,6 +1,7 @@ package io.ipinfo; import io.ipinfo.api.IPinfo; +import io.ipinfo.api.errors.ErrorResponseException; import io.ipinfo.api.errors.RateLimitedException; import io.ipinfo.api.model.ASNResponse; import io.ipinfo.api.model.IPResponse; @@ -388,4 +389,47 @@ public void testLookupResproxyEmpty() throws IOException { server.shutdown(); } } + + @Test + public void testServerErrorThrowsErrorResponseException() throws IOException { + MockWebServer server = new MockWebServer(); + server.enqueue(new MockResponse() + .setResponseCode(503) + .setBody("Service Temporarily Unavailable") + .addHeader("Content-Type", "text/plain")); + server.start(); + + OkHttpClient client = new OkHttpClient.Builder() + .addInterceptor(chain -> { + okhttp3.Request originalRequest = chain.request(); + okhttp3.HttpUrl newUrl = originalRequest.url().newBuilder() + .scheme("http") + .host(server.getHostName()) + .port(server.getPort()) + .build(); + okhttp3.Request newRequest = originalRequest.newBuilder() + .url(newUrl) + .build(); + return chain.proceed(newRequest); + }) + .build(); + + IPinfo ii = new IPinfo.Builder() + .setToken("test_token") + .setClient(client) + .build(); + + try { + ErrorResponseException ex = assertThrows( + ErrorResponseException.class, + () -> ii.lookupIP("8.8.8.8") + ); + assertEquals(503, ex.getStatusCode()); + assertTrue(ex.getMessage().contains("503"), "message should contain status code"); + assertTrue(ex.getMessage().contains("Service Temporarily Unavailable"), + "message should contain response body"); + } finally { + server.shutdown(); + } + } }