Skip to content

Commit bc6f817

Browse files
authored
Ovverride default ApiError message with the error message from the API response (#1447)
* Improve comments * Refactor to expose the error message
1 parent 6aff026 commit bc6f817

File tree

5 files changed

+51
-16
lines changed

5 files changed

+51
-16
lines changed

src/main/java/com/adyen/service/exception/ApiException.java

+6-3
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,19 @@
2525
import com.adyen.model.ApiError;
2626

2727
/**
28-
* API Exception class
28+
* API Exception thrown when there is an API error
29+
*
30+
* Check ApiError object to obtain the information about the error
2931
*/
3032
public class ApiException extends Exception {
31-
//Describes the error
33+
// Object with the information about the error
3234
private ApiError error;
3335

34-
//HTTP status code
36+
// HTTP status code
3537
private int statusCode;
3638

3739
private Map<String, List<String>> responseHeaders;
40+
// error JSON response
3841
private String responseBody;
3942

4043
public ApiException(String message, int statusCode) {

src/main/java/com/adyen/service/resource/Resource.java

+14-11
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,11 @@
2323
import com.adyen.Config;
2424
import com.adyen.Service;
2525
import com.adyen.constants.ApiConstants;
26-
import com.adyen.enums.Environment;
2726
import com.adyen.httpclient.ClientInterface;
2827
import com.adyen.httpclient.HTTPClientException;
2928
import com.adyen.model.ApiError;
3029
import com.adyen.model.RequestOptions;
3130
import com.adyen.service.exception.ApiException;
32-
import com.fasterxml.jackson.core.JacksonException;
33-
import com.fasterxml.jackson.databind.exc.MismatchedInputException;
34-
import com.google.gson.Gson;
3531

3632
import java.io.IOException;
3733
import java.util.List;
@@ -97,14 +93,14 @@ public String request(String json, RequestOptions requestOptions, ApiConstants.H
9793
/**
9894
* Request using json String with additional request parameters like idempotency-key
9995
*
100-
* @param json json
96+
* @param json body of the request
10197
* @param requestOptions request options
10298
* @param httpMethod http method
10399
* @param pathParams path parameters
104100
* @param queryString query string parameters
105-
* @throws ApiException apiException
106-
* @throws IOException IOException
107-
* @return request
101+
* @throws ApiException apiException when an API error is returned
102+
* @throws IOException IOException when an unexpected error occurs
103+
* @return JSON response
108104
*/
109105
public String request(String json, RequestOptions requestOptions, ApiConstants.HttpMethod httpMethod, Map<String, String> pathParams, Map<String, String> queryString) throws ApiException, IOException {
110106
ClientInterface clientInterface = service.getClient().getHttpClient();
@@ -113,12 +109,19 @@ public String request(String json, RequestOptions requestOptions, ApiConstants.H
113109
try {
114110
return clientInterface.request(resolve(pathParams), json, config, service.isApiKeyRequired(), requestOptions, httpMethod, queryString);
115111
} catch (HTTPClientException e) {
116-
apiException = new ApiException(e.getMessage(), e.getCode(), e.getResponseHeaders());
117-
apiException.setResponseBody(e.getResponseBody());
118112
try {
119-
apiException.setError(ApiError.fromJson(e.getResponseBody()));
113+
// build ApiException
114+
ApiError apiError = ApiError.fromJson(e.getResponseBody());
115+
String message = apiError.getMessage() + " ErrorCode: "+ apiError.getErrorCode();
116+
117+
apiException = new ApiException(message, e.getCode(), e.getResponseHeaders());
118+
apiException.setResponseBody(e.getResponseBody());
119+
apiException.setError(apiError);
120+
120121
} catch (Exception ignore) {
121122
// Response body could not be parsed (e.g. not JSON), raw response body available in ApiException#responseBody
123+
apiException = new ApiException(e.getMessage(), e.getCode(), e.getResponseHeaders());
124+
apiException.setResponseBody(e.getResponseBody());
122125
}
123126
}
124127
throw apiException;

src/test/java/com/adyen/BaseTest.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -304,15 +304,16 @@ protected PaymentRequest3ds2 create3DS2PaymentRequest() {
304304
}
305305

306306
/**
307-
* Returns a Client that has a mocked error response from fileName
307+
* Returns a Client that throws an exception with a given status and response
308308
*/
309309
protected Client createMockClientForErrors(int status, String fileName) {
310310
String response = getFileContents(fileName);
311311

312312
AdyenHttpClient adyenHttpClient = mock(AdyenHttpClient.class);
313313
HTTPClientException httpClientException = new HTTPClientException(status, "An error occured", new HashMap<>(), response);
314314
try {
315-
when(adyenHttpClient.request(anyString(), anyString(), any(Config.class), anyBoolean(), isNull(), any(), any())).thenThrow(httpClientException);
315+
when(adyenHttpClient.request(anyString(), anyString(), any(Config.class), anyBoolean(), isNull(), any(), any()))
316+
.thenThrow(httpClientException);
316317
} catch (IOException | HTTPClientException e) {
317318
fail("Unexpected exception: " + e.getMessage());
318319
}

src/test/java/com/adyen/service/ResourceTest.java

+19
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ public void testValidationException() throws IOException {
142142
fail("Expected exception");
143143
} catch (ApiException e) {
144144
assertEquals(422, e.getStatusCode());
145+
assertEquals("Required field 'reference' is not provided. ErrorCode: 130", e.getMessage());
145146
assertNotNull(e.getError());
146147
assertEquals("validation", e.getError().getErrorType());
147148
assertEquals("Required field 'reference' is not provided.", e.getError().getMessage());
@@ -160,10 +161,28 @@ public void testErrorRfc7807ValidationException() throws IOException {
160161
fail("Expected exception");
161162
} catch (ApiException e) {
162163
assertEquals(422, e.getStatusCode());
164+
assertEquals("Invalid legal entity information provided ErrorCode: 30_102", e.getMessage());
163165
assertNotNull(e.getError());
164166
assertEquals("https://docs.adyen.com/errors/validation", e.getError().getErrorType());
165167
assertEquals("Invalid legal entity information provided", e.getError().getMessage());
166168
assertEquals(1, e.getError().getInvalidFields().size());
167169
}
168170
}
171+
172+
// test error parsing when the JSON response is invalid
173+
@Test
174+
public void testValidationExceptionWithInvalidJsonResponse() throws IOException {
175+
Client client = createMockClientForErrors(422, "mocks/response-validation-error-invalid-json.json");
176+
177+
when(serviceMock.getClient()).thenReturn(client);
178+
try {
179+
Resource resource = new Resource(serviceMock, "", null);
180+
resource.request("request");
181+
182+
fail("Expected exception");
183+
} catch (ApiException e) {
184+
assertEquals(422, e.getStatusCode());
185+
assertNull(e.getError());
186+
}
187+
}
169188
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"status" : 422,
3+
"errorCode" : "130",
4+
"message" : "Required field 'reference' is not provided.",
5+
"errorType" : "validation",
6+
"pspReference" : "ABCDEFGHIJKLMNO",
7+
...
8+
// testing invalid JSON
9+
}

0 commit comments

Comments
 (0)