Skip to content

chore: support delegation of determining errors for an operation #489

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

Merged
merged 1 commit into from
Jan 13, 2022
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
Original file line number Diff line number Diff line change
Expand Up @@ -2044,7 +2044,7 @@ private void generateOperationResponseDeserializer(
// Write out the error deserialization dispatcher.
Set<StructureShape> errorShapes = HttpProtocolGeneratorUtils.generateErrorDispatcher(
context, operation, responseType, this::writeErrorCodeParser,
isErrorCodeInBody, this::getErrorBodyLocation);
isErrorCodeInBody, this::getErrorBodyLocation, this::getOperationErrors);
deserializingErrorShapes.addAll(errorShapes);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,21 @@
package software.amazon.smithy.typescript.codegen.integration;

import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import software.amazon.smithy.codegen.core.CodegenException;
import software.amazon.smithy.codegen.core.Symbol;
import software.amazon.smithy.codegen.core.SymbolProvider;
import software.amazon.smithy.codegen.core.SymbolReference;
import software.amazon.smithy.model.knowledge.HttpBinding.Location;
import software.amazon.smithy.model.knowledge.OperationIndex;
import software.amazon.smithy.model.pattern.SmithyPattern;
import software.amazon.smithy.model.shapes.MemberShape;
import software.amazon.smithy.model.shapes.OperationShape;
Expand Down Expand Up @@ -311,6 +314,7 @@ public static void writeRetryableTrait(TypeScriptWriter writer, StructureShape e
* @param errorCodeGenerator A consumer
* @param shouldParseErrorBody Flag indicating whether need to parse response body in this dispatcher function
* @param bodyErrorLocationModifier A function that returns the location of an error in a body given a data source.
* @param operationErrorsToShapes A map of error names to their {@link ShapeId}.
* @return A set of all error structure shapes for the operation that were dispatched to.
*/
static Set<StructureShape> generateErrorDispatcher(
Expand All @@ -319,11 +323,11 @@ static Set<StructureShape> generateErrorDispatcher(
SymbolReference responseType,
Consumer<GenerationContext> errorCodeGenerator,
boolean shouldParseErrorBody,
BiFunction<GenerationContext, String, String> bodyErrorLocationModifier
BiFunction<GenerationContext, String, String> bodyErrorLocationModifier,
BiFunction<GenerationContext, OperationShape, Map<String, ShapeId>> operationErrorsToShapes
) {
TypeScriptWriter writer = context.getWriter();
SymbolProvider symbolProvider = context.getSymbolProvider();
OperationIndex operationIndex = OperationIndex.of(context.getModel());
Set<StructureShape> errorShapes = new TreeSet<>();

Symbol symbol = symbolProvider.toSymbol(operation);
Expand Down Expand Up @@ -355,14 +359,14 @@ static Set<StructureShape> generateErrorDispatcher(
errorCodeGenerator.accept(context);
writer.openBlock("switch (errorCode) {", "}", () -> {
// Generate the case statement for each error, invoking the specific deserializer.
new TreeSet<>(operationIndex.getErrors(operation, context.getService())).forEach(error -> {
final ShapeId errorId = error.getId();
operationErrorsToShapes.apply(context, operation).forEach((name, errorId) -> {
StructureShape error = context.getModel().expectShape(errorId).asStructureShape().get();
// Track errors bound to the operation so their deserializers may be generated.
errorShapes.add(error);
Symbol errorSymbol = symbolProvider.toSymbol(error);
String errorDeserMethodName = ProtocolGenerator.getDeserFunctionName(errorSymbol,
context.getProtocolName()) + "Response";
writer.openBlock("case $S:\ncase $S:", " break;", errorId.getName(), errorId.toString(), () -> {
writer.openBlock("case $S:\ncase $S:", " break;", name, errorId.toString(), () -> {
// Dispatch to the error deserialization function.
String outputParam = shouldParseErrorBody ? "parsedOutput" : "output";
writer.openBlock("response = {", "}", () -> {
Expand Down Expand Up @@ -444,4 +448,24 @@ static void writeHostPrefix(GenerationContext context, OperationShape operation)
});
});
}

/**
* Returns a map of error names to their {@link ShapeId}.
*
* @param context the generation context
* @param operation the operation shape to retrieve errors for
* @return map of error names to {@link ShapeId}
*/
public static Map<String, ShapeId> getOperationErrors(GenerationContext context, OperationShape operation) {
return operation.getErrors().stream()
.collect(Collectors.toMap(
shapeId -> shapeId.getName(context.getService()),
Function.identity(),
(x, y) -> {
if (!x.equals(y)) {
throw new CodegenException(String.format("conflicting error shape ids: %s, %s", x, y));
}
return x;
}, TreeMap::new));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ private void generateOperationDeserializer(GenerationContext context, OperationS
// Write out the error deserialization dispatcher.
Set<StructureShape> errorShapes = HttpProtocolGeneratorUtils.generateErrorDispatcher(
context, operation, responseType, this::writeErrorCodeParser,
isErrorCodeInBody, this::getErrorBodyLocation);
isErrorCodeInBody, this::getErrorBodyLocation, this::getOperationErrors);
deserializingErrorShapes.addAll(errorShapes);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import software.amazon.smithy.codegen.core.CodegenException;
Expand Down Expand Up @@ -264,6 +265,17 @@ static String getSerdeFunctionSymbolComponent(Symbol symbol, Shape shape) {
}
}

/**
* Returns a map of error names to their {@link ShapeId}.
*
* @param context the generation context
* @param operation the operation shape to retrieve errors for
* @return map of error names to {@link ShapeId}
*/
default Map<String, ShapeId> getOperationErrors(GenerationContext context, OperationShape operation) {
return HttpProtocolGeneratorUtils.getOperationErrors(context, operation);
}

/**
* Context object used for service serialization and deserialization.
*/
Expand Down