Skip to content

Commit 59a6a5d

Browse files
committed
Update Error handling through async
This commit includes updates to handling errors to allow for streaming error body members. It also includes minor fixes for unused properties.
1 parent afd715a commit 59a6a5d

File tree

3 files changed

+38
-24
lines changed

3 files changed

+38
-24
lines changed

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

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -592,11 +592,10 @@ private void generateErrorDeserializer(GenerationContext context, StructureShape
592592
String errorDeserMethodName = ProtocolGenerator.getDeserFunctionName(errorSymbol,
593593
context.getProtocolName()) + "Response";
594594

595-
writer.openBlock("const $L = (\n"
595+
writer.openBlock("const $L = async (\n"
596596
+ " output: any,\n"
597597
+ " context: __SerdeContext\n"
598-
+ "): $T => {", "};", errorDeserMethodName, errorSymbol, () -> {
599-
598+
+ "): Promise<$T> => {", "};", errorDeserMethodName, errorSymbol, () -> {
600599
writer.openBlock("const contents: $T = {", "};", errorSymbol, () -> {
601600
writer.write("__type: $S,", error.getId().getName());
602601
writer.write("$$fault: $S,", error.getTrait(ErrorTrait.class).get().getValue());
@@ -677,6 +676,25 @@ private List<HttpBinding> readResponseBody(
677676
documentBindings.sort(Comparator.comparing(HttpBinding::getMemberName));
678677
List<HttpBinding> payloadBindings = bindingIndex.getResponseBindings(operationOrError, Location.PAYLOAD);
679678

679+
if (!documentBindings.isEmpty()) {
680+
readReponseBodyData(context, operationOrError);
681+
deserializeOutputDocument(context, operationOrError, documentBindings);
682+
return documentBindings;
683+
}
684+
if (!payloadBindings.isEmpty()) {
685+
readReponseBodyData(context, operationOrError);
686+
// There can only be one payload binding.
687+
HttpBinding binding = payloadBindings.get(0);
688+
Shape target = context.getModel().expectShape(binding.getMember().getTarget());
689+
writer.write("contents.$L = $L;", binding.getMemberName(), getOutputValue(context,
690+
Location.PAYLOAD, "data", binding.getMember(), target));
691+
return payloadBindings;
692+
}
693+
return ListUtils.of();
694+
}
695+
696+
private void readReponseBodyData(GenerationContext context, Shape operationOrError) {
697+
TypeScriptWriter writer = context.getWriter();
680698
// Prepare response body for deserializing.
681699
OperationIndex operationIndex = context.getModel().getKnowledge(OperationIndex.class);
682700
StructureShape operationOutputOrError = operationOrError.asStructureShape()
@@ -692,20 +710,6 @@ private List<HttpBinding> readResponseBody(
692710
// Otherwise, we collect the response body to structured object with parseBody().
693711
writer.write("const data: any = await parseBody(output.body, context);");
694712
}
695-
696-
if (!documentBindings.isEmpty()) {
697-
deserializeOutputDocument(context, operationOrError, documentBindings);
698-
return documentBindings;
699-
}
700-
if (!payloadBindings.isEmpty()) {
701-
// There can only be one payload binding.
702-
HttpBinding binding = payloadBindings.get(0);
703-
Shape target = context.getModel().expectShape(binding.getMember().getTarget());
704-
writer.write("contents.$L = $L;", binding.getMemberName(), getOutputValue(context,
705-
Location.PAYLOAD, "data", binding.getMember(), target));
706-
return payloadBindings;
707-
}
708-
return ListUtils.of();
709713
}
710714

711715
/**

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

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import software.amazon.smithy.model.shapes.Shape;
2727
import software.amazon.smithy.model.shapes.StructureShape;
2828
import software.amazon.smithy.model.traits.TimestampFormatTrait.Format;
29+
import software.amazon.smithy.typescript.codegen.TypeScriptDependency;
2930
import software.amazon.smithy.typescript.codegen.TypeScriptWriter;
3031
import software.amazon.smithy.typescript.codegen.integration.ProtocolGenerator.GenerationContext;
3132

@@ -146,7 +147,13 @@ static Set<StructureShape> generateErrorDispatcher(
146147
writer.write("body: data,");
147148
});
148149
}
149-
writer.write("let response: any;");
150+
151+
// Error responses must be at least SmithyException and MetadataBearer implementations.
152+
writer.addImport("SmithyException", "__SmithyException",
153+
TypeScriptDependency.AWS_SMITHY_CLIENT.packageName);
154+
writer.addImport("MetadataBearer", "__MetadataBearer",
155+
TypeScriptDependency.AWS_SDK_TYPES.packageName);
156+
writer.write("let response: __SmithyException & __MetadataBearer;");
150157
writer.write("let errorCode: String;");
151158
errorCodeGenerator.accept(context);
152159
writer.openBlock("switch (errorCode) {", "}", () -> {
@@ -160,7 +167,7 @@ static Set<StructureShape> generateErrorDispatcher(
160167
context.getProtocolName()) + "Response";
161168
writer.openBlock("case $S:\ncase $S:", " break;", errorId.getName(), errorId.toString(), () -> {
162169
// Dispatch to the error deserialization function.
163-
writer.write("response = $L(parsedOutput, context);", errorDeserMethodName);
170+
writer.write("response = await $L(parsedOutput, context);", errorDeserMethodName);
164171
});
165172
});
166173

@@ -169,8 +176,8 @@ static Set<StructureShape> generateErrorDispatcher(
169176
.write("errorCode = errorCode || \"UnknownError\";")
170177
.openBlock("response = {", "};", () -> {
171178
writer.write("__type: `$L#$${errorCode}`,", operation.getId().getNamespace());
172-
writer.write("$$name: errorCode,");
173179
writer.write("$$fault: \"client\",");
180+
writer.write("$$metadata: deserializeMetadata(output),");
174181
}).dedent();
175182
});
176183
writer.write("return Promise.reject(Object.assign(new Error(response.__type), response));");

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

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -238,8 +238,6 @@ private void generateOperationDeserializer(GenerationContext context, OperationS
238238
});
239239

240240
// Start deserializing the response.
241-
writer.write("const data: any = await parseBody(output.body, context)");
242-
writer.write("let contents: any = {};");
243241
readResponseBody(context, operation);
244242

245243
// Build the response with typing and metadata.
@@ -270,10 +268,10 @@ private void generateErrorDeserializer(GenerationContext context, StructureShape
270268
// Add the error shape to the list to generate functions for, since we'll use that.
271269
deserializingDocumentShapes.add(error);
272270

273-
writer.openBlock("const $L = (\n"
271+
writer.openBlock("const $L = async (\n"
274272
+ " output: any,\n"
275273
+ " context: __SerdeContext\n"
276-
+ "): $T => {", "};", errorDeserMethodName, errorSymbol, () -> {
274+
+ "): Promise<$T> => {", "};", errorDeserMethodName, errorSymbol, () -> {
277275
// First deserialize the body properly.
278276
writer.write("const deserialized: any = $L(output.body, context);",
279277
ProtocolGenerator.getDeserFunctionName(errorSymbol, context.getProtocolName()));
@@ -294,6 +292,11 @@ private void generateErrorDeserializer(GenerationContext context, StructureShape
294292

295293
private void readResponseBody(GenerationContext context, OperationShape operation) {
296294
operation.getOutput().ifPresent(outputId -> {
295+
// We only need to load the body and prepare a contents object if there is a response.
296+
TypeScriptWriter writer = context.getWriter();
297+
writer.write("const data: any = await parseBody(output.body, context)");
298+
writer.write("let contents: any = {};");
299+
297300
// If there's an output present, we know it's a structure.
298301
StructureShape outputShape = context.getModel().expectShape(outputId).asStructureShape().get();
299302

0 commit comments

Comments
 (0)