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

Add errorCode and errorDeclineCode fields to InvalidRequestException #771

Merged
merged 3 commits into from
Jan 18, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
54 changes: 33 additions & 21 deletions stripe/src/main/java/com/stripe/android/ErrorParser.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.stripe.android;

import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;

import org.json.JSONException;
Expand All @@ -17,44 +18,55 @@ class ErrorParser {

private static final String FIELD_CHARGE = "charge";
private static final String FIELD_CODE = "code";
private static final String FIELD_DECLINE_CODE = "decline_code";
private static final String FIELD_DECLINE_CODE = "declineCode";
private static final String FIELD_ERROR = "error";
private static final String FIELD_MESSAGE = "message";
private static final String FIELD_PARAM = "param";
private static final String FIELD_TYPE = "type";

@NonNull
static StripeError parseError(String rawError) {
StripeError stripeError = new StripeError();
static StripeError parseError(@Nullable String rawError) {
String charge = null;
String code = null;
String declineCode = null;
String message;
String param = null;
String type = null;
try {
JSONObject jsonError = new JSONObject(rawError);
JSONObject errorObject = jsonError.getJSONObject(FIELD_ERROR);
stripeError.charge = errorObject.optString(FIELD_CHARGE);
stripeError.code = errorObject.optString(FIELD_CODE);
stripeError.decline_code = errorObject.optString(FIELD_DECLINE_CODE);
stripeError.message = errorObject.optString(FIELD_MESSAGE);
stripeError.param = errorObject.optString(FIELD_PARAM);
stripeError.type = errorObject.optString(FIELD_TYPE);
charge = errorObject.optString(FIELD_CHARGE);
code = errorObject.optString(FIELD_CODE);
declineCode = errorObject.optString(FIELD_DECLINE_CODE);
message = errorObject.optString(FIELD_MESSAGE);
param = errorObject.optString(FIELD_PARAM);
type = errorObject.optString(FIELD_TYPE);
} catch (JSONException jsonException) {
stripeError.message = MALFORMED_RESPONSE_MESSAGE;
message = MALFORMED_RESPONSE_MESSAGE;
}
return stripeError;
return new StripeError(type, message, code, param, declineCode, charge);
}

/**
* A model for error objects sent from the server.
*/
static class StripeError {
public String type;
@Nullable public final String type;
@Nullable public final String message;
@Nullable public final String code;
@Nullable public final String param;
@Nullable public final String declineCode;
@Nullable public final String charge;

public String message;

public String code;

public String param;

public String decline_code;

public String charge;
StripeError(@Nullable String type, @Nullable String message, @Nullable String code,
@Nullable String param, @Nullable String declineCode,
@Nullable String charge) {
this.type = type;
this.message = message;
this.code = code;
this.param = param;
this.declineCode = declineCode;
this.charge = charge;
}
}
}
77 changes: 44 additions & 33 deletions stripe/src/main/java/com/stripe/android/StripeApiHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -729,19 +729,18 @@ static String getRetrieveTokenApiUrl(@NonNull String tokenId) {
return String.format(Locale.ROOT, "%s/%s", getApiUrl(), tokenId);
}

static void convertErrorsToExceptionsAndThrowIfNecessary(StripeResponse response) throws
InvalidRequestException,
APIException,
AuthenticationException,
CardException {
int rCode = response.getResponseCode();
String rBody = response.getResponseBody();
String requestId = null;
Map<String, List<String>> headers = response.getResponseHeaders();
List<String> requestIdList = headers == null ? null : headers.get("Request-Id");

static void convertErrorsToExceptionsAndThrowIfNecessary(@NonNull StripeResponse response)
throws InvalidRequestException, APIException, AuthenticationException, CardException {
final int rCode = response.getResponseCode();
final String rBody = response.getResponseBody();
final Map<String, List<String>> headers = response.getResponseHeaders();
final List<String> requestIdList = headers == null ? null : headers.get("Request-Id");

final String requestId;
if (requestIdList != null && requestIdList.size() > 0) {
requestId = requestIdList.get(0);
} else {
requestId = null;
}

if (rCode < 200 || rCode >= 300) {
Expand Down Expand Up @@ -999,9 +998,10 @@ private static List<Parameter> flattenParamsMap(Map<String, Object> params, Stri
return flatParams;
}

@NonNull
private static List<Parameter> flattenParamsValue(Object value, String keyPrefix)
throws InvalidRequestException {
List<Parameter> flatParams;
final List<Parameter> flatParams;
if (value instanceof Map<?, ?>) {
flatParams = flattenParamsMap((Map<String, Object>) value, keyPrefix);
} else if (value instanceof List<?>) {
Expand All @@ -1010,7 +1010,7 @@ private static List<Parameter> flattenParamsValue(Object value, String keyPrefix
throw new InvalidRequestException("You cannot set '" + keyPrefix + "' to an empty " +
"string. " + "We interpret empty strings as null in requests. " + "You may " +
"set '" + keyPrefix + "' to null to delete the property.", keyPrefix, null,
0, null);
0, null, null, null);
} else if (value == null) {
flatParams = new LinkedList<>();
flatParams.add(new Parameter(keyPrefix, ""));
Expand Down Expand Up @@ -1050,7 +1050,7 @@ private static byte[] getOutputBytes(
if (jsonData == null) {
throw new InvalidRequestException("Unable to create JSON data from parameters. "
+ "Please contact support@stripe.com for assistance.",
null, null, 0, null);
null, null, 0, null, null, null);
}
return jsonData.toString().getBytes(CHARSET);
} else {
Expand All @@ -1061,16 +1061,17 @@ private static byte[] getOutputBytes(
throw new InvalidRequestException("Unable to encode parameters to "
+ CHARSET
+ ". Please contact support@stripe.com for assistance.",
null, null, 0, e);
null, null, 0, null, null, e);
}
}

private static String getResponseBody(InputStream responseStream)
@Nullable
private static String getResponseBody(@NonNull InputStream responseStream)
throws IOException {
//\A is the beginning of
// the stream boundary
Scanner scanner = new Scanner(responseStream, CHARSET).useDelimiter("\\A");
String rBody = scanner.hasNext() ? scanner.next() : null;
final Scanner scanner = new Scanner(responseStream, CHARSET).useDelimiter("\\A");
final String rBody = scanner.hasNext() ? scanner.next() : null;
responseStream.close();
return rBody;
}
Expand Down Expand Up @@ -1103,16 +1104,14 @@ private static StripeResponse getStripeResponse(
method));
}
// trigger the request
int rCode = conn.getResponseCode();
String rBody;
Map<String, List<String>> headers;

final int rCode = conn.getResponseCode();
final String rBody;
if (rCode >= 200 && rCode < 300) {
rBody = getResponseBody(conn.getInputStream());
} else {
rBody = getResponseBody(conn.getErrorStream());
}
headers = conn.getHeaderFields();
final Map<String, List<String>> headers = conn.getHeaderFields();
return new StripeResponse(rCode, rBody, headers);

} catch (IOException e) {
Expand All @@ -1131,45 +1130,57 @@ private static StripeResponse getStripeResponse(
}
}

private static void handleAPIError(String rBody, int rCode, String requestId)
private static void handleAPIError(@Nullable String rBody, int rCode,
@Nullable String requestId)
throws InvalidRequestException, AuthenticationException,
CardException, APIException {

ErrorParser.StripeError stripeError = ErrorParser.parseError(rBody);
final ErrorParser.StripeError stripeError = ErrorParser.parseError(rBody);
switch (rCode) {
case 400:
case 400: {
throw new InvalidRequestException(
stripeError.message,
stripeError.param,
requestId,
rCode,
stripeError.code,
stripeError.declineCode,
null);
case 404:
}
case 404: {
throw new InvalidRequestException(
stripeError.message,
stripeError.param,
requestId,
rCode,
stripeError.code,
stripeError.declineCode,
null);
case 401:
}
case 401: {
throw new AuthenticationException(stripeError.message, requestId, rCode);
case 402:
}
case 402: {
throw new CardException(
stripeError.message,
requestId,
stripeError.code,
stripeError.param,
stripeError.decline_code,
stripeError.declineCode,
stripeError.charge,
rCode,
null);
case 403:
}
case 403: {
throw new PermissionException(stripeError.message, requestId, rCode);
case 429:
}
case 429: {
throw new RateLimitException(stripeError.message, stripeError.param, requestId,
rCode, null);
default:
}
default: {
throw new APIException(stripeError.message, requestId, rCode, null);
}
}
}

Expand Down
9 changes: 5 additions & 4 deletions stripe/src/main/java/com/stripe/android/StripeResponse.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
*/
class StripeResponse {

private String mResponseBody;
private int mResponseCode;
private Map<String, List<String>> mResponseHeaders;
@Nullable private final String mResponseBody;
private final int mResponseCode;
@Nullable private final Map<String, List<String>> mResponseHeaders;

/**
* Object constructor.
Expand All @@ -23,7 +23,7 @@ class StripeResponse {
*/
StripeResponse(
int responseCode,
String responseBody,
@Nullable String responseBody,
@Nullable Map<String, List<String>> responseHeaders) {
mResponseCode = responseCode;
mResponseBody = responseBody;
Expand All @@ -40,6 +40,7 @@ int getResponseCode() {
/**
* @return the {@link #mResponseBody response body}.
*/
@Nullable
String getResponseBody() {
return mResponseBody;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
package com.stripe.android.exception;

import android.support.annotation.Nullable;

/**
* An {@link Exception} that represents a failure to connect to Stripe's API.
*/
public class APIConnectionException extends StripeException {

public APIConnectionException(String message) {
super(message, null, 0);
public APIConnectionException(@Nullable String message) {
this(message, null);
}

public APIConnectionException(String message, Throwable e) {
public APIConnectionException(@Nullable String message, @Nullable Throwable e) {
super(message, null, 0, e);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package com.stripe.android.exception;

import android.support.annotation.Nullable;

/**
* An {@link Exception} that represents an internal problem with Stripe's servers.
*/
public class APIException extends StripeException {

public APIException(String message, String requestId, Integer statusCode, Throwable e) {
public APIException(@Nullable String message, @Nullable String requestId,
@Nullable Integer statusCode, @Nullable Throwable e) {
super(message, requestId, statusCode, e);
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package com.stripe.android.exception;

import android.support.annotation.Nullable;

/**
* An {@link Exception} that represents a failure to authenticate yourself to the server.
*/
public class AuthenticationException extends StripeException {

public AuthenticationException(String message, String requestId, Integer statusCode) {
public AuthenticationException(@Nullable String message, @Nullable String requestId,
@Nullable Integer statusCode) {
super(message, requestId, statusCode);
}
}
Original file line number Diff line number Diff line change
@@ -1,39 +1,47 @@
package com.stripe.android.exception;

import android.support.annotation.Nullable;

/**
* An {@link Exception} indicating that there is a problem with a Card used for a request.
* Card errors are the most common type of error you should expect to handle.
* They result when the user enters a card that can't be charged for some reason.
*/
public class CardException extends StripeException {

private String code;
private String param;
private String declineCode;
private String charge;
@Nullable private final String mCode;
@Nullable private final String mParam;
@Nullable private final String mDeclineCode;
@Nullable private final String mCharge;

public CardException(String message, String requestId, String code, String param,
String declineCode, String charge, Integer statusCode, Throwable e) {
public CardException(@Nullable String message, @Nullable String requestId,
@Nullable String code, @Nullable String param,
@Nullable String declineCode, @Nullable String charge,
@Nullable Integer statusCode, @Nullable Throwable e) {
super(message, requestId, statusCode, e);
this.code = code;
this.param = param;
this.declineCode = declineCode;
this.charge = charge;
mCode = code;
mParam = param;
mDeclineCode = declineCode;
mCharge = charge;
}

@Nullable
public String getCode() {
return code;
return mCode;
}

@Nullable
public String getParam() {
return param;
return mParam;
}

@Nullable
public String getDeclineCode() {
return declineCode;
return mDeclineCode;
}

@Nullable
public String getCharge() {
return charge;
return mCharge;
}
}
Loading