-
Notifications
You must be signed in to change notification settings - Fork 916
Support modeled exceptions in event streams #655
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,6 +16,12 @@ | |
package software.amazon.awssdk.awscore.internal.protocol.json; | ||
|
||
import com.fasterxml.jackson.databind.JsonNode; | ||
import java.util.Arrays; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.stream.Collectors; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
import software.amazon.awssdk.annotations.SdkInternalApi; | ||
import software.amazon.awssdk.core.internal.protocol.json.JsonContent; | ||
import software.amazon.awssdk.http.SdkHttpFullResponse; | ||
|
@@ -29,6 +35,17 @@ public class JsonErrorCodeParser implements ErrorCodeParser { | |
*/ | ||
public static final String X_AMZN_ERROR_TYPE = "x-amzn-ErrorType"; | ||
|
||
static final String ERROR_CODE_HEADER = ":error-code"; | ||
|
||
static final String EXCEPTION_TYPE_HEADER = ":exception-type"; | ||
|
||
private static final Logger log = LoggerFactory.getLogger(JsonErrorCodeParser.class); | ||
|
||
/** | ||
* List of header keys that represent the error code sent by service. | ||
* Response should only contain one of these headers | ||
*/ | ||
private final List<String> errorCodeHeaders; | ||
private final String errorCodeFieldName; | ||
|
||
public JsonErrorCodeParser() { | ||
|
@@ -37,6 +54,7 @@ public JsonErrorCodeParser() { | |
|
||
public JsonErrorCodeParser(String errorCodeFieldName) { | ||
this.errorCodeFieldName = errorCodeFieldName == null ? "__type" : errorCodeFieldName; | ||
this.errorCodeHeaders = Arrays.asList(X_AMZN_ERROR_TYPE, ERROR_CODE_HEADER, EXCEPTION_TYPE_HEADER); | ||
} | ||
|
||
/** | ||
|
@@ -60,7 +78,29 @@ public String parseErrorCode(SdkHttpFullResponse response, JsonContent jsonConte | |
* present in the header. | ||
*/ | ||
private String parseErrorCodeFromHeader(SdkHttpFullResponse response) { | ||
String headerValue = response.firstMatchingHeader(X_AMZN_ERROR_TYPE).orElse(null); | ||
Map<String, List<String>> filteredHeaders = response.headers().entrySet().stream() | ||
.filter(e -> errorCodeHeaders.contains(e.getKey())) | ||
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); | ||
|
||
if (filteredHeaders.isEmpty()) { | ||
return null; | ||
} | ||
|
||
if (filteredHeaders.size() > 1) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is the customer experience in this situation? We generally try to be as resilient as possible when unmarshlaling the exceptions so we can preserve as much info as possible about the error. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are you saying we should combine all the error codes? I think its confusing if service multiple headers representing the error code with different values. If they do, maybe we can select the first option and return it? what do you think? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Whatever we do we should try to fail as gracefully a possible so that we still generate a service exception rather than a runtime one. I'm thinking selecting the first one we find and log a warning. |
||
log.warn("Response contains multiple headers representing the error code: " + filteredHeaders.keySet()); | ||
} | ||
|
||
String headerKey = filteredHeaders.keySet().stream().findFirst().get(); | ||
String headerValue = filteredHeaders.get(headerKey).get(0); | ||
|
||
if (X_AMZN_ERROR_TYPE.equals(headerKey)) { | ||
return parseErrorCodeFromXAmzErrorType(headerValue); | ||
} | ||
|
||
return headerValue; | ||
} | ||
|
||
private String parseErrorCodeFromXAmzErrorType(String headerValue) { | ||
if (headerValue != null) { | ||
int separator = headerValue.indexOf(':'); | ||
if (separator != -1) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this will be okay to do but you may want to validate this by importing the Dev preview package to see if any unexpected source changes occur in the generated client.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I validated the shape names but makes sense to review the entire generated code
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I verified that there is no diff in the generated code.