diff --git a/src/main/java/com/skyflow/errors/HttpStatus.java b/src/main/java/com/skyflow/errors/HttpStatus.java new file mode 100644 index 00000000..2cdadbb0 --- /dev/null +++ b/src/main/java/com/skyflow/errors/HttpStatus.java @@ -0,0 +1,15 @@ +package com.skyflow.errors; + +public enum HttpStatus { + BAD_REQUEST("Bad Request"); + + private final String httpStatus; + + HttpStatus(String httpStatus) { + this.httpStatus = httpStatus; + } + + public String getHttpStatus() { + return httpStatus; + } +} diff --git a/src/main/java/com/skyflow/errors/SkyflowException.java b/src/main/java/com/skyflow/errors/SkyflowException.java index 6cff3cdd..1db1ed19 100644 --- a/src/main/java/com/skyflow/errors/SkyflowException.java +++ b/src/main/java/com/skyflow/errors/SkyflowException.java @@ -1,13 +1,9 @@ package com.skyflow.errors; -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import com.google.gson.JsonSyntaxException; +import com.google.gson.*; import java.util.List; import java.util.Map; -import java.util.Objects; public class SkyflowException extends Exception { private String requestId; @@ -37,28 +33,27 @@ public SkyflowException(int code, String message) { super(message); this.httpCode = code; this.message = message; + this.httpStatus = HttpStatus.BAD_REQUEST.getHttpStatus(); + this.details = new JsonArray(); } public SkyflowException(int httpCode, Throwable cause, Map> responseHeaders, String responseBody) { - this(cause); + super(cause); this.httpCode = httpCode; - String contentType = responseHeaders.get("content-type").get(0); setRequestId(responseHeaders); - if (Objects.equals(contentType, "application/json")) { - setResponseBody(responseBody); - } else if (Objects.equals(contentType, "text/plain")) { - this.message = responseBody; - } + setResponseBody(responseBody); } private void setResponseBody(String responseBody) { try { if (responseBody != null) { this.responseBody = JsonParser.parseString(responseBody).getAsJsonObject(); - setGrpcCode(); - setHttpStatus(); - setMessage(); - setDetails(); + if (this.responseBody.get("error") != null) { + setGrpcCode(); + setHttpStatus(); + setMessage(); + setDetails(); + } } } catch (JsonSyntaxException e) { throw new RuntimeException(e); @@ -72,24 +67,28 @@ public String getRequestId() { private void setRequestId(Map> responseHeaders) { if (responseHeaders != null) { List ids = responseHeaders.get("x-request-id"); - this.requestId = ids.get(0); + this.requestId = ids == null ? null : ids.get(0); } } private void setMessage() { - this.message = ((JsonObject) responseBody.get("error")).get("message").getAsString(); + JsonElement messageElement = ((JsonObject) responseBody.get("error")).get("message"); + this.message = messageElement == null ? null : messageElement.getAsString(); } private void setGrpcCode() { - this.grpcCode = ((JsonObject) responseBody.get("error")).get("grpc_code").getAsInt(); + JsonElement grpcElement = ((JsonObject) responseBody.get("error")).get("grpc_code"); + this.grpcCode = grpcElement == null ? null : grpcElement.getAsInt(); } private void setHttpStatus() { - this.httpStatus = ((JsonObject) responseBody.get("error")).get("http_status").getAsString(); + JsonElement statusElement = ((JsonObject) responseBody.get("error")).get("http_status"); + this.httpStatus = statusElement == null ? null : statusElement.getAsString(); } private void setDetails() { - this.details = ((JsonObject) responseBody.get("error")).get("details").getAsJsonArray(); + JsonElement detailsElement = ((JsonObject) responseBody.get("error")).get("details"); + this.details = detailsElement == null ? null : detailsElement.getAsJsonArray(); } public int getHttpCode() { diff --git a/src/main/java/com/skyflow/utils/HttpUtility.java b/src/main/java/com/skyflow/utils/HttpUtility.java index 664cc9da..b8e9283b 100644 --- a/src/main/java/com/skyflow/utils/HttpUtility.java +++ b/src/main/java/com/skyflow/utils/HttpUtility.java @@ -1,7 +1,7 @@ package com.skyflow.utils; +import com.google.gson.JsonElement; import com.google.gson.JsonObject; -import com.google.gson.JsonParser; import com.skyflow.errors.SkyflowException; import java.io.*; @@ -9,7 +9,9 @@ import java.net.URL; import java.nio.charset.StandardCharsets; import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.Objects; public final class HttpUtility { @@ -33,18 +35,18 @@ public static String sendRequest(String method, URL url, JsonObject params, Map< connection.setRequestProperty("content-type", "application/json"); connection.setRequestProperty("Accept", "*/*"); - if (headers != null && headers.size() > 0) { + if (headers != null && !headers.isEmpty()) { for (Map.Entry entry : headers.entrySet()) connection.setRequestProperty(entry.getKey(), entry.getValue()); // append dynamic boundary if content-type is multipart/form-data if (headers.containsKey("content-type")) { - if (headers.get("content-type") == "multipart/form-data") { + if (Objects.equals(headers.get("content-type"), "multipart/form-data")) { connection.setRequestProperty("content-type", "multipart/form-data; boundary=" + boundary); } } } - if (params != null && params.size() > 0) { + if (params != null && !params.isEmpty()) { connection.setDoOutput(true); try (DataOutputStream wr = new DataOutputStream(connection.getOutputStream())) { byte[] input = null; @@ -63,12 +65,12 @@ public static String sendRequest(String method, URL url, JsonObject params, Map< } } - int status = connection.getResponseCode(); + int httpCode = connection.getResponseCode(); String requestID = connection.getHeaderField("x-request-id"); HttpUtility.requestID = requestID.split(",")[0]; - + Map> responseHeaders = connection.getHeaderFields(); Reader streamReader; - if (status > 299) { + if (httpCode > 299) { if (connection.getErrorStream() != null) streamReader = new InputStreamReader(connection.getErrorStream()); else { @@ -86,9 +88,8 @@ public static String sendRequest(String method, URL url, JsonObject params, Map< response.append(inputLine); } - if (status > 299) { - String errorMsg = appendRequestIdToErrorObj(status, response.toString(), requestID); - throw new SkyflowException(errorMsg); + if (httpCode > 299) { + throw new SkyflowException(httpCode, new Throwable(), responseHeaders, response.toString()); } } finally { if (in != null) { @@ -127,13 +128,14 @@ public static String formatJsonToMultiPartFormDataString(JsonObject requestBody, private static HashMap convertJsonToMap(JsonObject json, String rootKey) { HashMap currentMap = new HashMap<>(); - for (Object key : json.keySet()) { - Object currentValue = json.get((String) key); - String currentKey = rootKey.length() != 0 ? rootKey + '[' + key.toString() + ']' : rootKey + key.toString(); - if (currentValue instanceof JsonObject) { + Map jsonMap = json.asMap(); + for (String key : jsonMap.keySet()) { + JsonElement currentValue = jsonMap.get(key); + String currentKey = !rootKey.isEmpty() ? rootKey + '[' + key + ']' : rootKey + key; + if (currentValue.isJsonObject()) { currentMap.putAll(convertJsonToMap((JsonObject) currentValue, currentKey)); } else { - currentMap.put(currentKey, currentValue.toString()); + currentMap.put(currentKey, currentValue.getAsString()); } } return currentMap; @@ -156,22 +158,6 @@ public static String appendRequestId(String message, String requestId) { return message; } - public static String appendRequestIdToErrorObj(int status, String error, String requestId) throws SkyflowException { - if (requestId != null && !requestId.isEmpty()) { - JsonObject errorObject = (JsonObject) new JsonParser().parse(error); - JsonObject tempError = (JsonObject) errorObject.get("error"); - if (tempError != null) { - String message = String.valueOf(tempError.get("message")); - message = message + " - requestId: " + requestId; - - tempError.addProperty("message", message); - errorObject.add("error", tempError); - } - error = errorObject.toString(); - } - return error; - } - private static String makeFormEncodeKeyValuePair(String key, String value) { return key + "=" + value + "&"; } diff --git a/src/main/java/com/skyflow/vault/connection/InvokeConnectionResponse.java b/src/main/java/com/skyflow/vault/connection/InvokeConnectionResponse.java index a30a44c9..a2d44d99 100644 --- a/src/main/java/com/skyflow/vault/connection/InvokeConnectionResponse.java +++ b/src/main/java/com/skyflow/vault/connection/InvokeConnectionResponse.java @@ -2,22 +2,23 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; -import com.google.gson.JsonObject; + +import java.util.HashMap; public class InvokeConnectionResponse { - private final JsonObject data; - private final JsonObject metadata; + private final Object data; + private final HashMap metadata; - public InvokeConnectionResponse(JsonObject data, JsonObject metadata) { + public InvokeConnectionResponse(Object data, HashMap metadata) { this.data = data; this.metadata = metadata; } - public JsonObject getData() { + public Object getData() { return data; } - public JsonObject getMetadata() { + public HashMap getMetadata() { return metadata; } diff --git a/src/main/java/com/skyflow/vault/controller/ConnectionController.java b/src/main/java/com/skyflow/vault/controller/ConnectionController.java index 0bb2251e..68a39751 100644 --- a/src/main/java/com/skyflow/vault/controller/ConnectionController.java +++ b/src/main/java/com/skyflow/vault/controller/ConnectionController.java @@ -26,7 +26,7 @@ import java.util.HashMap; import java.util.Map; -public class ConnectionController extends ConnectionClient { +public final class ConnectionController extends ConnectionClient { public ConnectionController(ConnectionConfig connectionConfig, Credentials credentials) { super(connectionConfig, credentials); } @@ -65,8 +65,8 @@ public InvokeConnectionResponse invoke(InvokeConnectionRequest invokeConnectionR String response = HttpUtility.sendRequest(requestMethod.name(), new URL(filledURL), requestBody, headers); JsonObject data = JsonParser.parseString(response).getAsJsonObject(); - JsonObject metadata = new JsonObject(); - metadata.addProperty("requestId", HttpUtility.getRequestID()); + HashMap metadata = new HashMap<>(); + metadata.put("requestId", HttpUtility.getRequestID()); connectionResponse = new InvokeConnectionResponse(data, metadata); LogUtil.printInfoLog(InfoLogs.INVOKE_CONNECTION_REQUEST_RESOLVED.getLog()); } catch (IOException e) { diff --git a/src/test/java/com/skyflow/utils/HttpUtilityTests.java b/src/test/java/com/skyflow/utils/HttpUtilityTests.java index 816f1504..f7214690 100644 --- a/src/test/java/com/skyflow/utils/HttpUtilityTests.java +++ b/src/test/java/com/skyflow/utils/HttpUtilityTests.java @@ -43,7 +43,7 @@ public class HttpUtilityTests { @Before public void setup() throws IOException { expected = "{\"status\":\"success\"}"; - expectedError = "{\"status\":\"something went wrong\"}"; + expectedError = "{\"error\":{\"grpc_code\":123,\"http_code\":500,\"message\":\"something went wrong\",\"http_status\":\"internal server error\",\"details\":[]}}\n"; mockConnection = Mockito.mock(HttpURLConnection.class); given(mockConnection.getInputStream()).willReturn(new ByteArrayInputStream(expected.getBytes())); given(mockConnection.getErrorStream()).willReturn(new ByteArrayInputStream(expectedError.getBytes())); @@ -115,7 +115,11 @@ public void testSendRequestError() { given(mockConnection.getResponseCode()).willReturn(500); String response = httpUtility.sendRequest("GET", url, null, null); } catch (SkyflowException e) { - Assert.assertEquals(expectedError, e.getMessage()); + Assert.assertEquals(500, e.getHttpCode()); + Assert.assertEquals(new Integer(123), e.getGrpcCode()); + Assert.assertEquals("internal server error", e.getHttpStatus()); + Assert.assertEquals("something went wrong", e.getMessage()); + Assert.assertTrue(e.getDetails().isEmpty()); } catch (Exception e) { fail(INVALID_EXCEPTION_THROWN); } diff --git a/src/test/java/com/skyflow/vault/connection/InvokeConnectionTests.java b/src/test/java/com/skyflow/vault/connection/InvokeConnectionTests.java index 90bc4c1e..a29a3335 100644 --- a/src/test/java/com/skyflow/vault/connection/InvokeConnectionTests.java +++ b/src/test/java/com/skyflow/vault/connection/InvokeConnectionTests.java @@ -423,12 +423,12 @@ public void testInvokeConnectionResponse() { JsonObject data = new JsonObject(); data.addProperty("test_key_1", "test_value_1"); data.addProperty("test_key_2", "test_value_2"); - JsonObject metadata = new JsonObject(); - metadata.addProperty("requestId", "12345"); + HashMap metadata = new HashMap<>(); + metadata.put("requestId", "12345"); InvokeConnectionResponse connectionResponse = new InvokeConnectionResponse(data, metadata); String responseString = "{\"data\":{\"test_key_1\":\"test_value_1\",\"test_key_2\":\"test_value_2\"}," + "\"metadata\":{\"requestId\":\"12345\"}}"; - Assert.assertEquals(2, connectionResponse.getData().size()); + Assert.assertNotNull(connectionResponse.getData()); Assert.assertEquals(responseString, connectionResponse.toString()); Assert.assertEquals(1, connectionResponse.getMetadata().size()); } catch (Exception e) { diff --git a/src/test/java/com/skyflow/vault/controller/VaultControllerTests.java b/src/test/java/com/skyflow/vault/controller/VaultControllerTests.java index ca2e85d9..66621003 100644 --- a/src/test/java/com/skyflow/vault/controller/VaultControllerTests.java +++ b/src/test/java/com/skyflow/vault/controller/VaultControllerTests.java @@ -7,6 +7,7 @@ import com.skyflow.enums.LogLevel; import com.skyflow.errors.ErrorCode; import com.skyflow.errors.ErrorMessage; +import com.skyflow.errors.HttpStatus; import com.skyflow.errors.SkyflowException; import com.skyflow.generated.rest.ApiClient; import com.skyflow.generated.rest.api.TokensApi; @@ -155,8 +156,8 @@ public void testInvalidRequestInTokenizeMethod() { ); Assert.assertNull(e.getRequestId()); Assert.assertNull(e.getGrpcCode()); - Assert.assertNull(e.getHttpStatus()); - Assert.assertNull(e.getDetails()); + Assert.assertTrue(e.getDetails().isEmpty()); + Assert.assertEquals(HttpStatus.BAD_REQUEST.getHttpStatus(), e.getHttpStatus()); } }