Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose additional error response properties in the Exception #123

Merged
merged 4 commits into from
May 3, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,7 @@ If you need to handle different error scenarios you need to catch first `APIExce

The APIExplorer includes a list of response messages for each endpoint. You can get a clue of what went wrong by asking the Http status code: `exception.getStatusCode()`. i.e. a `status_code=403` would mean that the token has an insufficient scope.

An error code will be included to categorize the type of error, you can get it by calling `exception.getError()`. If you want to see a user friendly description of what happened and why the request is failing check the `exception.getDescription()`.
An error code will be included to categorize the type of error, you can get it by calling `exception.getError()`. If you want to see a user friendly description of what happened and why the request is failing check the `exception.getDescription()`. Finally, if the error response includes additional properties they can be obtained by calling `exception.getValue("{THE_KEY}")`.


```
Expand Down
24 changes: 20 additions & 4 deletions src/main/java/com/auth0/exception/APIException.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.auth0.exception;

import java.util.Collections;
import java.util.Map;

/**
Expand All @@ -21,6 +22,7 @@ public class APIException extends Auth0Exception {
private String error;
private String description;
private int statusCode;
private Map<String, Object> values;

public APIException(String payload, int statusCode, Throwable cause) {
super(createMessage(payload, statusCode), cause);
Expand All @@ -30,8 +32,9 @@ public APIException(String payload, int statusCode, Throwable cause) {

public APIException(Map<String, Object> values, int statusCode) {
super(createMessage(obtainExceptionMessage(values), statusCode));
this.error = obtainExceptionError(values);
this.description = obtainExceptionMessage(values);
this.values = Collections.unmodifiableMap(values);
this.error = obtainExceptionError(this.values);
this.description = obtainExceptionMessage(this.values);
this.statusCode = statusCode;
}

Expand All @@ -55,6 +58,19 @@ public String getError() {
return error;
}

/**
* Returns a value from the error map, if any.
*
* @param key key of the value to return
* @return the value if found or null
*/
public Object getValue(String key) {
if (values == null) {
return null;
}
return values.get(key);
}

/**
* Getter for the exception user friendly description of why the request failed.
* i.e. the description may say which query parameters are valid for that endpoint.
Expand All @@ -75,9 +91,9 @@ private static String obtainExceptionMessage(Map<String, Object> values) {
}
if (values.containsKey("description")) {
Object description = values.get("description");
if(description instanceof String) {
if (description instanceof String) {
return (String) description;
} else{
} else {
PasswordStrengthErrorParser policy = new PasswordStrengthErrorParser((Map<String, Object>) description);
return policy.getDescription();
}
Expand Down
1 change: 1 addition & 0 deletions src/test/java/com/auth0/client/MockServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public class MockServer {
public static final String AUTH_ERROR_WITH_ERROR_DESCRIPTION = "src/test/resources/auth/error_with_error_description.json";
public static final String AUTH_ERROR_WITH_ERROR = "src/test/resources/auth/error_with_error.json";
public static final String AUTH_ERROR_WITH_DESCRIPTION = "src/test/resources/auth/error_with_description.json";
public static final String AUTH_ERROR_WITH_DESCRIPTION_AND_EXTRA_PROPERTIES = "src/test/resources/auth/error_with_description_and_extra_properties.json";
public static final String AUTH_ERROR_PLAINTEXT = "src/test/resources/auth/error_plaintext.json";
public static final String MGMT_ERROR_WITH_MESSAGE = "src/test/resources/mgmt/error_with_message.json";
public static final String MGMT_CLIENT_GRANTS_LIST = "src/test/resources/mgmt/client_grants_list.json";
Expand Down
27 changes: 26 additions & 1 deletion src/test/java/com/auth0/net/CustomRequestTest.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package com.auth0.net;

import com.auth0.client.MockServer;
import com.auth0.exception.Auth0Exception;
import com.auth0.exception.APIException;
import com.auth0.exception.Auth0Exception;
import com.auth0.json.auth.TokenHolder;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
Expand Down Expand Up @@ -214,6 +214,30 @@ public void shouldParseJSONErrorResponseWithError() throws Exception {
assertThat(authException.getStatusCode(), is(400));
}

@SuppressWarnings("RedundantCast")
@Test
public void shouldParseJSONErrorResponseWithDescriptionAndExtraProperties() throws Exception {
CustomRequest<List> request = new CustomRequest<>(client, server.getBaseUrl(), "GET", listType);
server.jsonResponse(AUTH_ERROR_WITH_DESCRIPTION_AND_EXTRA_PROPERTIES, 400);
Exception exception = null;
try {
request.execute();
server.takeRequest();
} catch (Exception e) {
exception = e;
}
assertThat(exception, is(notNullValue()));
assertThat(exception, is(instanceOf(APIException.class)));
assertThat(exception.getCause(), is(nullValue()));
assertThat(exception.getMessage(), is("Request failed with status code 400: Multifactor authentication required"));
APIException authException = (APIException) exception;
assertThat(authException.getDescription(), is("Multifactor authentication required"));
assertThat(authException.getError(), is("mfa_required"));
assertThat(authException.getValue("mfa_token"), is((Object) "Fe26...Ha"));
assertThat(authException.getValue("non_existing_key"), is(nullValue()));
assertThat(authException.getStatusCode(), is(400));
}

@Test
public void shouldParseJSONErrorResponseWithDescription() throws Exception {
CustomRequest<List> request = new CustomRequest<>(client, server.getBaseUrl(), "GET", listType);
Expand Down Expand Up @@ -274,6 +298,7 @@ public void shouldParsePlainTextErrorResponse() throws Exception {
APIException authException = (APIException) exception;
assertThat(authException.getDescription(), is("A plain-text error response"));
assertThat(authException.getError(), is(nullValue()));
assertThat(authException.getValue("non_existing_key"), is(nullValue()));
assertThat(authException.getStatusCode(), is(400));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"error": "mfa_required",
"error_description": "Multifactor authentication required",
"mfa_token": "Fe26...Ha"
}