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

generate server-side exceptions as classes #502

Merged
merged 21 commits into from
Feb 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
e761852
rename SmithyException to SdkException in client SDK
AllanZhengYP Jan 25, 2022
22bede6
Revert "rename SmithyException to SdkException in client SDK"
AllanZhengYP Jan 26, 2022
f31d283
generate exception in classes for http bindings and rpc
AllanZhengYP Jan 27, 2022
62e9f5f
update deser to throw new exception classes
AllanZhengYP Jan 28, 2022
e221f5c
re-export SdkException in client index
AllanZhengYP Jan 28, 2022
7506172
update comments
AllanZhengYP Jan 28, 2022
1b7a543
rename SdkException to ServiceException
AllanZhengYP Jan 28, 2022
3fb542e
fix parsing default exception without body.Error
AllanZhengYP Jan 28, 2022
1fc92a4
keep Message in error interface for backwards compatibility
AllanZhengYP Jan 28, 2022
40e99fd
address feedbacks
AllanZhengYP Feb 2, 2022
509eb09
fix checkstyle failure for copyright year
AllanZhengYP Feb 2, 2022
ddd6de4
consolidate ssdk and client sdk error classes
AllanZhengYP Feb 6, 2022
07e953a
rename ClientException to SmithyClient in server-common package
AllanZhengYP Feb 13, 2022
bdf4f88
export the server-side base exception SmithyException from the client…
AllanZhengYP Feb 14, 2022
e3eb0e1
fix http bunding decorateServiceException parameters
AllanZhengYP Feb 14, 2022
42d43bb
apply writeAdditionalExports() of TypeScriptIntegration interface to …
AllanZhengYP Feb 16, 2022
786c91a
address feedback to not extend framework errors
AllanZhengYP Feb 16, 2022
bdbd9d6
chore: update yarn.lock
AllanZhengYP Feb 16, 2022
ca7741d
do not reexport base exception for ssdk; export base exception in cli…
AllanZhengYP Feb 17, 2022
d2a1497
rename SmithyException in ssdk to ServiceException
AllanZhengYP Feb 17, 2022
2d6daea
generate service specific exception class for client sdk
AllanZhengYP Feb 17, 2022
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
1 change: 0 additions & 1 deletion .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,5 @@ smithy-typescript-integ-tests/* @adamthom-amzn @gosar @JordonPhillips

# These are all specific to SSDK functionality.
smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/ServerCommandGenerator.java @adamthom-amzn @gosar @JordonPhillips
smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/ServerErrorGenerator.java @adamthom-amzn @gosar @JordonPhillips
smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/ServerGenerator.java @adamthom-amzn @gosar @JordonPhillips
smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/ServerSymbolVisitor.java @adamthom-amzn @gosar @JordonPhillips
2 changes: 1 addition & 1 deletion config/checkstyle/checkstyle.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
<!-- Files must contain a copyright header. -->
<module name="RegexpHeader">
<property name="header"
value="/\*\n \* Copyright 20(19|20|21) Amazon\.com, Inc\. or its affiliates\. All Rights Reserved\.\n"/>
value="/\*\n \* Copyright 20(19|20|21|22) Amazon\.com, Inc\. or its affiliates\. All Rights Reserved\.\n"/>
<property name="fileExtensions" value="java"/>
</module>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,6 @@ public Void serviceShape(ServiceShape shape) {

if (settings.generateServerSdk()) {
generateServiceInterface(shape);
generateServerErrors(shape);
}

if (protocolGenerator != null) {
Expand Down Expand Up @@ -470,20 +469,6 @@ private void generateServiceInterface(ServiceShape shape) {
});
}

private void generateServerErrors(ServiceShape service) {
final OperationIndex operationIndex = OperationIndex.of(model);

TopDownIndex.of(model)
.getContainedOperations(service)
.stream()
.flatMap(o -> operationIndex.getErrors(o, service).stream())
.distinct()
.sorted()
.forEachOrdered(error -> writers.useShapeWriter(service, symbolProvider, writer -> {
new ServerErrorGenerator(settings, model, error, symbolProvider, writer).run();
}));
}

private void generateCommands(ServiceShape shape) {
// Generate each operation for the service.
TopDownIndex topDownIndex = TopDownIndex.of(model);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -741,9 +741,9 @@ private void writeServerResponseTest(OperationShape operation, HttpResponseTestC
writer.write("const request = new HttpRequest({method: 'POST', hostname: 'example.com'});");

// Create a new serializer factory that always returns our test serializer.
writer.addImport("SmithyException", "__SmithyException", "@aws-sdk/types");
writer.addImport("ServiceException", "__ServiceException", "@aws-smithy/server-common");
writer.addImport("OperationSerializer", "__OperationSerializer", "@aws-smithy/server-common");
writer.openBlock("const serFn: (op: $1T) => __OperationSerializer<$2T<{}>, $1T, __SmithyException> = (op) =>"
writer.openBlock("const serFn: (op: $1T) => __OperationSerializer<$2T<{}>, $1T, __ServiceException> = (op) =>"
+ " { return new TestSerializer(); };", serviceOperationsSymbol, serviceSymbol);

writer.addImport("serializeFrameworkException", null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ static void writeIndex(

// write export statement for models
writer.write("export * from \"./models\";");

// Write each custom export.
for (TypeScriptIntegration integration : integrations) {
integration.writeAdditionalExports(settings, model, symbolProvider, writer);
}

fileManifest.writeFile(Paths.get(CodegenUtils.SOURCE_FOLDER, "index.ts").toString(), writer.toString());
}

Expand Down Expand Up @@ -121,11 +127,5 @@ private static void writeClientExports(
if (operations.stream().anyMatch(operation -> operation.hasTrait(WaitableTrait.ID))) {
writer.write("export * from \"./waiters\";");
}

// Write each custom export.
for (TypeScriptIntegration integration : integrations) {
integration.writeAdditionalExports(settings, model, symbolProvider, writer);
}
fileManifest.writeFile(Paths.get(CodegenUtils.SOURCE_FOLDER, "index.ts").toString(), writer.toString());
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ static void generateServiceHandler(SymbolProvider symbolProvider,
writer.write("private readonly service: $T<Context>;", serviceSymbol);
writer.write("private readonly mux: __Mux<$S, $T>;", serviceShape.getId().getName(), operationsType);
writer.write("private readonly serializerFactory: <T extends $T>(operation: T) => "
+ "__OperationSerializer<$T<Context>, T, __SmithyException>;",
+ "__OperationSerializer<$T<Context>, T, __ServiceException>;",
operationsType, serviceSymbol);
writer.write("private readonly serializeFrameworkException: (e: __SmithyFrameworkException, "
+ "ctx: __ServerSerdeContext) => Promise<__HttpResponse>;");
Expand All @@ -87,7 +87,7 @@ static void generateServiceHandler(SymbolProvider symbolProvider,
writer.write("service: $T<Context>,", serviceSymbol);
writer.write("mux: __Mux<$S, $T>,", serviceShape.getId().getName(), operationsType);
writer.write("serializerFactory:<T extends $T>(op: T) => "
+ "__OperationSerializer<$T<Context>, T, __SmithyException>,",
+ "__OperationSerializer<$T<Context>, T, __ServiceException>,",
operationsType, serviceSymbol);
writer.write("serializeFrameworkException: (e: __SmithyFrameworkException, ctx: __ServerSerdeContext) "
+ "=> Promise<__HttpResponse>,");
Expand Down Expand Up @@ -208,7 +208,7 @@ private static void addCommonHandlerImports(TypeScriptWriter writer) {
writer.addImport("SmithyFrameworkException", "__SmithyFrameworkException", "@aws-smithy/server-common");
writer.addImport("HttpRequest", "__HttpRequest", "@aws-sdk/protocol-http");
writer.addImport("HttpResponse", "__HttpResponse", "@aws-sdk/protocol-http");
writer.addImport("SmithyException", "__SmithyException", "@aws-sdk/types");
writer.addImport("ServiceException", "__ServiceException", "@aws-smithy/server-common");
writer.addImport("ValidationCustomizer", "__ValidationCustomizer", "@aws-smithy/server-common");
}

Expand All @@ -226,7 +226,7 @@ private static void writeHandleFunction(TypeScriptWriter writer) {
writer.write("request: __HttpRequest,");
writer.write("context: Context,");
writer.write("operationName: O,");
writer.write("serializer: __OperationSerializer<S, O, __SmithyException>,");
writer.write("serializer: __OperationSerializer<S, O, __ServiceException>,");
writer.write("operation: __Operation<__OperationInput<S[O]>, __OperationOutput<S[O]>, Context>,");
writer.write("serializeFrameworkException: (e: __SmithyFrameworkException, "
+ "ctx: __ServerSerdeContext) => Promise<__HttpResponse>,");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import software.amazon.smithy.codegen.core.Symbol;
import software.amazon.smithy.codegen.core.SymbolProvider;
import software.amazon.smithy.codegen.core.SymbolReference;
Expand Down Expand Up @@ -140,61 +139,6 @@ private void renderNonErrorStructure() {
renderStructureNamespace(config, includeValidation);
}

/**
* Error structures generate interfaces that extend from SmithyException
* and add the appropriate fault property.
*
* <p>Given the following Smithy structure:
*
* <pre>{@code
* namespace smithy.example
*
* @error("client")
* structure NoSuchResource {
* @required
* resourceType: String
* }
* }</pre>
*
* <p>The following TypeScript is generated:
*
* <pre>{@code
* import {
* SmithyException as __SmithyException
* } from "@aws-sdk/types";
*
* export interface NoSuchResource extends __SmithyException, $MetadataBearer {
* name: "NoSuchResource";
* $fault: "client";
* resourceType: string | undefined;
* }
* }</pre>
*/
private void renderErrorStructure() {
ErrorTrait errorTrait = shape.getTrait(ErrorTrait.class).orElseThrow(IllegalStateException::new);
Symbol symbol = symbolProvider.toSymbol(shape);
writer.writeShapeDocs(shape);

// Find symbol references with the "extends" property, and add SmithyException.
writer.addImport("SmithyException", "__SmithyException", "@aws-sdk/types");
String extendsFrom = Stream.concat(
Stream.of("__SmithyException"),
symbol.getReferences().stream()
.filter(ref -> ref.getProperty(SymbolVisitor.IMPLEMENTS_INTERFACE_PROPERTY).isPresent())
.map(SymbolReference::getAlias)
).collect(Collectors.joining(", "));

writer.openBlock("export interface $L extends $L {", symbol.getName(), extendsFrom);
writer.write("name: $S;", shape.getId().getName());
writer.write("$$fault: $S;", errorTrait.getValue());
HttpProtocolGeneratorUtils.writeRetryableTrait(writer, shape, ";");
StructuredMemberWriter structuredMemberWriter = new StructuredMemberWriter(
model, symbolProvider, shape.getAllMembers().values());
structuredMemberWriter.writeMembers(writer, shape);
writer.closeBlock("}"); // interface
writer.write("");
}

private void renderStructureNamespace(StructuredMemberWriter structuredMemberWriter, boolean includeValidation) {
Symbol symbol = symbolProvider.toSymbol(shape);
writer.openBlock("export namespace $L {", "}", symbol.getName(), () -> {
Expand Down Expand Up @@ -228,4 +172,68 @@ private void renderStructureNamespace(StructuredMemberWriter structuredMemberWri
});
});
}

/**
* Error structures generate classes that extend from service base exception
* (ServiceException in case of server SDK), and add the appropriate fault
* property.
*
* <p>Given the following Smithy structure:
*
* <pre>{@code
* namespace smithy.example
*
* @error("client")
* structure NoSuchResource {
* @required
* resourceType: String
* }
* }</pre>
*
* <p>The following TypeScript is generated:
*
* <pre>{@code
* import { ExceptionOptionType as __ExceptionOptionType } from "@aws-sdk/smithy-client";
* import { FooServiceException as __BaseException } from "./FooServiceException";
* // In server SDK:
* // import { ServiceException as __BaseException } from "@aws-smithy/server-common";
*
* export class NoSuchResource extends __BaseException {
* name: "NoSuchResource";
* $fault: "client";
* resourceType: string | undefined;
* // @internal
* constructor(opts: __ExceptionOptionType<NoSuchResource, __BaseException>) {
* super({
* name: "NoSuchResource",
* $fault: "client",
* ...opts
* });
* Object.setPrototypeOf(this, NoSuchResource.prototype);
* this.resourceType = opts.resourceType;
* }
* }
* }</pre>
*/
private void renderErrorStructure() {
ErrorTrait errorTrait = shape.getTrait(ErrorTrait.class).orElseThrow(IllegalStateException::new);
Symbol symbol = symbolProvider.toSymbol(shape);
writer.writeShapeDocs(shape);
boolean isServerSdk = this.includeValidation;
writer.openBlock("export class $T extends $L {", symbol, "__BaseException");
writer.write("readonly name: $1S = $1S;", shape.getId().getName());
writer.write("readonly $$fault: $1S = $1S;", errorTrait.getValue());
if (!isServerSdk) {
HttpProtocolGeneratorUtils.writeRetryableTrait(writer, shape, ";");
}
StructuredMemberWriter structuredMemberWriter = new StructuredMemberWriter(model, symbolProvider,
shape.getAllMembers().values());
// since any error interface must extend from JavaScript Error interface, message member is already
// required in the JavaScript Error interface
structuredMemberWriter.skipMembers.add("message");
structuredMemberWriter.writeMembers(writer, shape);
structuredMemberWriter.writeErrorConstructor(writer, shape, isServerSdk);
writer.closeBlock("}");
writer.write("");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -124,22 +124,29 @@ void writeMemberFilterSensitiveLog(TypeScriptWriter writer, MemberShape member,
}

/**
* Writes a constructor function that takes in an object allowing modeled fields to be initialized.
* Writes constructor of SDK exception classes.
*/
void writeConstructor(TypeScriptWriter writer, Shape shape) {
writer.openBlock("constructor(opts: {", "}) {", () -> {
writeMembers(writer, shape);
void writeErrorConstructor(TypeScriptWriter writer, Shape shape, boolean isServerSdk) {
ErrorTrait errorTrait = shape.getTrait(ErrorTrait.class).orElseThrow(IllegalStateException::new);
Symbol symbol = symbolProvider.toSymbol(shape);
if (!isServerSdk) {
writer.writeDocs("@internal");
}
writer.addImport("ExceptionOptionType", "__ExceptionOptionType",
TypeScriptDependency.AWS_SMITHY_CLIENT.packageName);
writer.openBlock("constructor(opts: __ExceptionOptionType<$L, __BaseException>) {", symbol.getName());
writer.openBlock("super({", "});", () -> {
writer.write("name: $S,", shape.getId().getName());
writer.write("$$fault: $S,", errorTrait.getValue());
writer.write("...opts");
});
writer.indent();

writer.write("Object.setPrototypeOf(this, $L.prototype);", symbol.getName());
for (MemberShape member : members) {
if (skipMembers.contains(member.getMemberName())) {
continue;
}

writer.write("this.${1L} = opts.${1L};", getSanitizedMemberName(member));
}

writer.closeBlock("}");
}

Expand Down
Loading