Skip to content

Commit a56d352

Browse files
authored
chore: support delegation of determining errors for an operation (#489)
1 parent e83e9b3 commit a56d352

File tree

4 files changed

+44
-8
lines changed

4 files changed

+44
-8
lines changed

smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/integration/HttpBindingProtocolGenerator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2044,7 +2044,7 @@ private void generateOperationResponseDeserializer(
20442044
// Write out the error deserialization dispatcher.
20452045
Set<StructureShape> errorShapes = HttpProtocolGeneratorUtils.generateErrorDispatcher(
20462046
context, operation, responseType, this::writeErrorCodeParser,
2047-
isErrorCodeInBody, this::getErrorBodyLocation);
2047+
isErrorCodeInBody, this::getErrorBodyLocation, this::getOperationErrors);
20482048
deserializingErrorShapes.addAll(errorShapes);
20492049
}
20502050

smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/integration/HttpProtocolGeneratorUtils.java

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,21 @@
1616
package software.amazon.smithy.typescript.codegen.integration;
1717

1818
import java.util.List;
19+
import java.util.Map;
1920
import java.util.Optional;
2021
import java.util.Set;
22+
import java.util.TreeMap;
2123
import java.util.TreeSet;
2224
import java.util.function.BiFunction;
2325
import java.util.function.Consumer;
26+
import java.util.function.Function;
2427
import java.util.logging.Logger;
28+
import java.util.stream.Collectors;
2529
import software.amazon.smithy.codegen.core.CodegenException;
2630
import software.amazon.smithy.codegen.core.Symbol;
2731
import software.amazon.smithy.codegen.core.SymbolProvider;
2832
import software.amazon.smithy.codegen.core.SymbolReference;
2933
import software.amazon.smithy.model.knowledge.HttpBinding.Location;
30-
import software.amazon.smithy.model.knowledge.OperationIndex;
3134
import software.amazon.smithy.model.pattern.SmithyPattern;
3235
import software.amazon.smithy.model.shapes.MemberShape;
3336
import software.amazon.smithy.model.shapes.OperationShape;
@@ -311,6 +314,7 @@ public static void writeRetryableTrait(TypeScriptWriter writer, StructureShape e
311314
* @param errorCodeGenerator A consumer
312315
* @param shouldParseErrorBody Flag indicating whether need to parse response body in this dispatcher function
313316
* @param bodyErrorLocationModifier A function that returns the location of an error in a body given a data source.
317+
* @param operationErrorsToShapes A map of error names to their {@link ShapeId}.
314318
* @return A set of all error structure shapes for the operation that were dispatched to.
315319
*/
316320
static Set<StructureShape> generateErrorDispatcher(
@@ -319,11 +323,11 @@ static Set<StructureShape> generateErrorDispatcher(
319323
SymbolReference responseType,
320324
Consumer<GenerationContext> errorCodeGenerator,
321325
boolean shouldParseErrorBody,
322-
BiFunction<GenerationContext, String, String> bodyErrorLocationModifier
326+
BiFunction<GenerationContext, String, String> bodyErrorLocationModifier,
327+
BiFunction<GenerationContext, OperationShape, Map<String, ShapeId>> operationErrorsToShapes
323328
) {
324329
TypeScriptWriter writer = context.getWriter();
325330
SymbolProvider symbolProvider = context.getSymbolProvider();
326-
OperationIndex operationIndex = OperationIndex.of(context.getModel());
327331
Set<StructureShape> errorShapes = new TreeSet<>();
328332

329333
Symbol symbol = symbolProvider.toSymbol(operation);
@@ -355,14 +359,14 @@ static Set<StructureShape> generateErrorDispatcher(
355359
errorCodeGenerator.accept(context);
356360
writer.openBlock("switch (errorCode) {", "}", () -> {
357361
// Generate the case statement for each error, invoking the specific deserializer.
358-
new TreeSet<>(operationIndex.getErrors(operation, context.getService())).forEach(error -> {
359-
final ShapeId errorId = error.getId();
362+
operationErrorsToShapes.apply(context, operation).forEach((name, errorId) -> {
363+
StructureShape error = context.getModel().expectShape(errorId).asStructureShape().get();
360364
// Track errors bound to the operation so their deserializers may be generated.
361365
errorShapes.add(error);
362366
Symbol errorSymbol = symbolProvider.toSymbol(error);
363367
String errorDeserMethodName = ProtocolGenerator.getDeserFunctionName(errorSymbol,
364368
context.getProtocolName()) + "Response";
365-
writer.openBlock("case $S:\ncase $S:", " break;", errorId.getName(), errorId.toString(), () -> {
369+
writer.openBlock("case $S:\ncase $S:", " break;", name, errorId.toString(), () -> {
366370
// Dispatch to the error deserialization function.
367371
String outputParam = shouldParseErrorBody ? "parsedOutput" : "output";
368372
writer.openBlock("response = {", "}", () -> {
@@ -444,4 +448,24 @@ static void writeHostPrefix(GenerationContext context, OperationShape operation)
444448
});
445449
});
446450
}
451+
452+
/**
453+
* Returns a map of error names to their {@link ShapeId}.
454+
*
455+
* @param context the generation context
456+
* @param operation the operation shape to retrieve errors for
457+
* @return map of error names to {@link ShapeId}
458+
*/
459+
public static Map<String, ShapeId> getOperationErrors(GenerationContext context, OperationShape operation) {
460+
return operation.getErrors().stream()
461+
.collect(Collectors.toMap(
462+
shapeId -> shapeId.getName(context.getService()),
463+
Function.identity(),
464+
(x, y) -> {
465+
if (!x.equals(y)) {
466+
throw new CodegenException(String.format("conflicting error shape ids: %s, %s", x, y));
467+
}
468+
return x;
469+
}, TreeMap::new));
470+
}
447471
}

smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/integration/HttpRpcProtocolGenerator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,7 @@ private void generateOperationDeserializer(GenerationContext context, OperationS
373373
// Write out the error deserialization dispatcher.
374374
Set<StructureShape> errorShapes = HttpProtocolGeneratorUtils.generateErrorDispatcher(
375375
context, operation, responseType, this::writeErrorCodeParser,
376-
isErrorCodeInBody, this::getErrorBodyLocation);
376+
isErrorCodeInBody, this::getErrorBodyLocation, this::getOperationErrors);
377377
deserializingErrorShapes.addAll(errorShapes);
378378
}
379379

smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/integration/ProtocolGenerator.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import java.util.Collection;
1919
import java.util.List;
20+
import java.util.Map;
2021
import java.util.function.Supplier;
2122
import java.util.stream.Collectors;
2223
import software.amazon.smithy.codegen.core.CodegenException;
@@ -264,6 +265,17 @@ static String getSerdeFunctionSymbolComponent(Symbol symbol, Shape shape) {
264265
}
265266
}
266267

268+
/**
269+
* Returns a map of error names to their {@link ShapeId}.
270+
*
271+
* @param context the generation context
272+
* @param operation the operation shape to retrieve errors for
273+
* @return map of error names to {@link ShapeId}
274+
*/
275+
default Map<String, ShapeId> getOperationErrors(GenerationContext context, OperationShape operation) {
276+
return HttpProtocolGeneratorUtils.getOperationErrors(context, operation);
277+
}
278+
267279
/**
268280
* Context object used for service serialization and deserialization.
269281
*/

0 commit comments

Comments
 (0)