From 0ce99b9b81ec91af80b77906b103cdb586f0baba Mon Sep 17 00:00:00 2001 From: Isaiah Vita <82135527+isaiahvita@users.noreply.github.com> Date: Wed, 27 Sep 2023 08:51:57 -0700 Subject: [PATCH] Upgrade to Smithy 1.39 (#2290) --- .github/workflows/codegen.yml | 17 +- .github/workflows/go.yml | 2 +- codegen/gradle.properties | 2 +- .../smithy-aws-go-codegen/build.gradle.kts | 1 + .../AwsEndpointResolverBuiltInGenerator.java | 192 ++++---- .../smithy/aws/go/codegen/AwsFnProvider.java | 7 +- .../aws/go/codegen/AwsProtocolUtils.java | 22 + .../awsrestjson/api_op_HttpPayloadTraits.go | 2 +- .../api_op_HttpPayloadTraitsWithMediaType.go | 2 +- .../api_op_HttpPayloadWithStructure.go | 2 +- .../api_op_HttpPayloadWithUnion.go | 113 +++++ .../api_op_HttpPayloadWithUnion_test.go | 238 ++++++++++ .../awsrestjson/api_op_JsonUnions_test.go | 25 ++ .../protocoltest/awsrestjson/deserializers.go | 186 ++++++++ .../protocoltest/awsrestjson/generated.json | 2 + .../protocoltest/awsrestjson/serializers.go | 84 ++++ .../protocoltest/awsrestjson/types/types.go | 16 + .../awsrestjson/types/types_exported_test.go | 18 + .../jsonrpc/api_op_JsonUnions_test.go | 25 ++ .../jsonrpc10/api_op_JsonUnions_test.go | 25 ++ .../restxml/api_op_HttpPayloadTraits.go | 2 +- .../api_op_HttpPayloadTraitsWithMediaType.go | 2 +- .../api_op_HttpPayloadWithStructure.go | 2 +- .../restxml/api_op_HttpPayloadWithUnion.go | 113 +++++ .../api_op_HttpPayloadWithUnion_test.go | 249 +++++++++++ .../restxml/api_op_XmlMapWithXmlNamespace.go | 112 +++++ .../api_op_XmlMapWithXmlNamespace_test.go | 239 ++++++++++ .../protocoltest/restxml/deserializers.go | 415 ++++++++++++++++++ internal/protocoltest/restxml/generated.json | 4 + internal/protocoltest/restxml/serializers.go | 214 +++++++++ internal/protocoltest/restxml/types/types.go | 16 + .../restxml/types/types_exported_test.go | 18 + 32 files changed, 2256 insertions(+), 111 deletions(-) create mode 100644 internal/protocoltest/awsrestjson/api_op_HttpPayloadWithUnion.go create mode 100644 internal/protocoltest/awsrestjson/api_op_HttpPayloadWithUnion_test.go create mode 100644 internal/protocoltest/restxml/api_op_HttpPayloadWithUnion.go create mode 100644 internal/protocoltest/restxml/api_op_HttpPayloadWithUnion_test.go create mode 100644 internal/protocoltest/restxml/api_op_XmlMapWithXmlNamespace.go create mode 100644 internal/protocoltest/restxml/api_op_XmlMapWithXmlNamespace_test.go diff --git a/.github/workflows/codegen.yml b/.github/workflows/codegen.yml index efd865a488c..f4a2c86c8da 100644 --- a/.github/workflows/codegen.yml +++ b/.github/workflows/codegen.yml @@ -6,6 +6,10 @@ on: pull_request: branches: [ main ] +env: + # get owner of the repository. used by forks. + SMITHY_GO_REPOSITORY: ${{ github.event.pull_request.head.repo.owner.login }}/smithy-go + jobs: codegen-test: name: SDK Codegen Test @@ -38,17 +42,18 @@ jobs: with: go-version: ${{ matrix.go-version }} - - uses: actions/checkout@v2 - with: - repository: aws/smithy-go - path: tmp-smithy-go + - name: Find smithy-go + shell: bash + env: + RUNNER_TMPDIR: ${{ runner.temp }} + run: ./ci-find-smithy-go.sh - name: Build and publish smithy-go - working-directory: tmp-smithy-go + working-directory: ${{ runner.temp }}/smithy-go run: make smithy-publish-local - name: Cleanup smithy-go - run: rm -rf tmp-smithy-go + run: rm -rf ${{ runner.temp }}/smithy-go - name: SDK Codegen run: make smithy-generate diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 2cb7944e8e8..1b377bdf1b4 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -11,7 +11,7 @@ on: env: EACHMODULE_CONCURRENCY: 2 - SMITHY_GO_REPOSITORY: ${{ vars.SMITHY_GO_REPOSITORY }} + SMITHY_GO_REPOSITORY: ${{ github.event.pull_request.head.repo.owner.login }}/smithy-go GIT_PAT: ${{ secrets.CI_GIT_PAT}} jobs: diff --git a/codegen/gradle.properties b/codegen/gradle.properties index 544c84cf73e..3f06b8d01fe 100644 --- a/codegen/gradle.properties +++ b/codegen/gradle.properties @@ -1,2 +1,2 @@ -smithyVersion=1.37.0 +smithyVersion=1.39.0 smithyGradleVersion=0.7.0 diff --git a/codegen/smithy-aws-go-codegen/build.gradle.kts b/codegen/smithy-aws-go-codegen/build.gradle.kts index 49377e62703..aab3dac6f16 100644 --- a/codegen/smithy-aws-go-codegen/build.gradle.kts +++ b/codegen/smithy-aws-go-codegen/build.gradle.kts @@ -44,6 +44,7 @@ dependencies { api("software.amazon.smithy:smithy-aws-traits:$smithyVersion") api("software.amazon.smithy:smithy-aws-iam-traits:$smithyVersion") api("software.amazon.smithy:smithy-aws-cloudformation-traits:$smithyVersion") + api("software.amazon.smithy:smithy-aws-endpoints:$smithyVersion") api("software.amazon.smithy:smithy-diff:$smithyVersion") api("software.amazon.smithy.go:smithy-go-codegen:0.1.0") testImplementation("org.junit.jupiter:junit-jupiter-api:5.4.0") diff --git a/codegen/smithy-aws-go-codegen/src/main/java/software/amazon/smithy/aws/go/codegen/AwsEndpointResolverBuiltInGenerator.java b/codegen/smithy-aws-go-codegen/src/main/java/software/amazon/smithy/aws/go/codegen/AwsEndpointResolverBuiltInGenerator.java index 4423c18f29b..9c43ac7627a 100644 --- a/codegen/smithy-aws-go-codegen/src/main/java/software/amazon/smithy/aws/go/codegen/AwsEndpointResolverBuiltInGenerator.java +++ b/codegen/smithy-aws-go-codegen/src/main/java/software/amazon/smithy/aws/go/codegen/AwsEndpointResolverBuiltInGenerator.java @@ -27,6 +27,7 @@ import software.amazon.smithy.rulesengine.language.syntax.parameters.Parameters; import software.amazon.smithy.utils.StringUtils; +import java.util.Iterator; import java.util.Map; import java.util.Optional; import java.util.function.Consumer; @@ -68,8 +69,8 @@ public void writeAdditionalFiles( .add(generateBuiltInResolverMethod(parameters)) .compose(); - for (Parameter parameter : parameters.toList()) { - if (parameter.getBuiltIn().isPresent()) { + for(Iterator iter = parameters.iterator(); iter.hasNext();){ + if (iter.next().getBuiltIn().isPresent()) { writerFactory.accept("endpoints.go", settings.getModuleName(), writer -> { writer.write("$W", content); }); @@ -145,41 +146,43 @@ private GoWriter.Writable generateBuiltInImplementationType(Parameters parameter private GoWriter.Writable generateBuiltInResolverMembers(Parameters parameters) { return (GoWriter w) -> { - parameters.toList().stream().filter( - p -> p.getBuiltIn().isPresent()) - .forEach(parameter -> { - String template = """ - $W - $L $T - """; - GoWriter.Writable docs; - Symbol paramSymbol; - if (parameter.getBuiltIn().get().equals("SDK::Endpoint")) { - template = """ - $W - $L $P - """; - docs = goDocTemplate( - "Base endpoint that can potentially be modified during Endpoint resolution."); - paramSymbol = parameterAsSymbol(parameter); - } else if (parameter.getBuiltIn().get().equals("AWS::UseFIPS")) { - docs = goDocTemplate("Sourced BuiltIn value in a historical enabled or disabled state."); - paramSymbol = SymbolUtils - .createValueSymbolBuilder("FIPSEndpointState", AwsGoDependency.AWS_CORE).build(); - } else if (parameter.getBuiltIn().get().equals("AWS::UseDualStack")) { - docs = goDocTemplate("Sourced BuiltIn value in a historical enabled or disabled state."); - paramSymbol = SymbolUtils - .createValueSymbolBuilder("DualStackEndpointState", AwsGoDependency.AWS_CORE) - .build(); - } else { - docs = parameter.getDocumentation().isPresent() - ? goDocTemplate(parameter.getDocumentation().get()) - : goDocTemplate(""); - paramSymbol = parameterAsSymbol(parameter); - } - w.write(template, docs, getExportedParameterName(parameter), paramSymbol); - w.insertTrailingNewline(); - }); + for(Iterator iter = parameters.iterator(); iter.hasNext();){ + Parameter parameter = iter.next(); + if (!parameter.getBuiltIn().isPresent()) { + continue; + } + String template = """ + $W + $L $T + """; + GoWriter.Writable docs; + Symbol paramSymbol; + if (parameter.getBuiltIn().get().equals("SDK::Endpoint")) { + template = """ + $W + $L $P + """; + docs = goDocTemplate( + "Base endpoint that can potentially be modified during Endpoint resolution."); + paramSymbol = parameterAsSymbol(parameter); + } else if (parameter.getBuiltIn().get().equals("AWS::UseFIPS")) { + docs = goDocTemplate("Sourced BuiltIn value in a historical enabled or disabled state."); + paramSymbol = SymbolUtils + .createValueSymbolBuilder("FIPSEndpointState", AwsGoDependency.AWS_CORE).build(); + } else if (parameter.getBuiltIn().get().equals("AWS::UseDualStack")) { + docs = goDocTemplate("Sourced BuiltIn value in a historical enabled or disabled state."); + paramSymbol = SymbolUtils + .createValueSymbolBuilder("DualStackEndpointState", AwsGoDependency.AWS_CORE) + .build(); + } else { + docs = parameter.getDocumentation().isPresent() + ? goDocTemplate(parameter.getDocumentation().get()) + : goDocTemplate(""); + paramSymbol = parameterAsSymbol(parameter); + } + w.write(template, docs, getExportedParameterName(parameter), paramSymbol); + w.insertTrailingNewline(); + } }; } @@ -196,10 +199,11 @@ private GoWriter.Writable generateBuiltInResolverMethod(Parameters parameters) { """), AwsEndpointResolverBuiltInGenerator.BUILTIN_RESOLVER_IMPLEMENTATION_TYPE, EndpointResolutionGenerator.PARAMETERS_TYPE_NAME); - - parameters.toList().stream().filter( - p -> p.getBuiltIn().isPresent()) - .forEach(parameter -> { + for(Iterator iter = parameters.iterator(); iter.hasNext();){ + Parameter parameter = iter.next(); + if (!parameter.getBuiltIn().isPresent()) { + continue; + } if (parameter.getBuiltIn().get().equals("SDK::Endpoint")) { writer.write("$W", generateSdkEndpointBuiltInResolver(parameter)); } else if (parameter.getBuiltIn().get().equals("AWS::Region")) { @@ -211,20 +215,20 @@ private GoWriter.Writable generateBuiltInResolverMethod(Parameters parameters) { } else if (parameter.getType() == ParameterType.STRING) { writer.write( "params.$L = $T(b.$L)", - parameter.getName().asString(), + parameter.getName().getName().getValue(), SymbolUtils.createValueSymbolBuilder("String", AwsGoDependency.AWS_CORE).build(), getExportedParameterName(parameter)); } else if (parameter.getType() == ParameterType.BOOLEAN) { writer.write( "params.$L = $T(b.$L)", - parameter.getName().asString(), + parameter.getName().getName().getValue(), SymbolUtils.createValueSymbolBuilder("Bool", AwsGoDependency.AWS_CORE).build(), getExportedParameterName(parameter)); } else { throw new CodegenException( String.format("Invalid Builtin %s", parameter.getBuiltIn().get())); } - }); + } writer.write( """ @@ -242,7 +246,7 @@ private GoWriter.Writable generateSdkEndpointBuiltInResolver(Parameter parameter params.$L = b.Endpoint """, - parameter.getName().asString()); + parameter.getName().getName().getValue()); }; } @@ -260,14 +264,14 @@ private GoWriter.Writable generateAwsRegionBuiltInResolver(Parameter parameter) """, - parameter.getName().asString(), + parameter.getName().getName().getValue(), SymbolUtils.createValueSymbolBuilder("String", AwsGoDependency.AWS_CORE).build()); }; } private GoWriter.Writable generateAwsFipsBuiltInResolver(Parameter parameter) { return (GoWriter writer) -> { - String paramName = parameter.getName().asString(); + String paramName = parameter.getName().getName().getValue(); writer.write( """ if b.UseFIPS == $T { @@ -287,7 +291,7 @@ private GoWriter.Writable generateAwsFipsBuiltInResolver(Parameter parameter) { private GoWriter.Writable generateAwsDualStackBuiltInResolver(Parameter parameter) { return (GoWriter writer) -> { - String paramName = parameter.getName().asString(); + String paramName = parameter.getName().getName().getValue(); writer.write( """ if b.UseDualStack == $T { @@ -340,56 +344,58 @@ public void renderEndpointBuiltInInitialization(GoWriter writer, Parameters para } private GoWriter.Writable generateBuiltInInitializeFieldMembers(Parameters parameters) { - return (GoWriter writer) -> { - parameters.toList().stream().filter( - p -> p.getBuiltIn().isPresent()) - .forEach(parameter -> { - if (parameter.getBuiltIn().get().equals("SDK::Endpoint")) { - writer.write("$L: options.BaseEndpoint,", getExportedParameterName(parameter)); - writer.insertTrailingNewline(); - } - if (parameter.getBuiltIn().get().equals("AWS::Region")) { - writer.write("$L: options.Region,", getExportedParameterName(parameter)); - writer.insertTrailingNewline(); - } - if (parameter.getBuiltIn().get().equals("AWS::UseFIPS")) { - writer.write("$L: options.$L.$L,", getExportedParameterName(parameter), - "EndpointOptions", USE_FIPS_ENDPOINT_OPTION); - writer.insertTrailingNewline(); - } - if (parameter.getBuiltIn().get().equals("AWS::UseDualStack")) { - writer.write("$L: options.$L.$L,", getExportedParameterName(parameter), - "EndpointOptions", DUAL_STACK_ENDPOINT_OPTION); - writer.insertTrailingNewline(); - } - if (parameter.getBuiltIn().get().equals("AWS::S3::ForcePathStyle")) { - writer.write("$L: options.UsePathStyle,", getExportedParameterName(parameter)); - writer.insertTrailingNewline(); - } - if (parameter.getBuiltIn().get().equals("AWS::S3::Accelerate")) { - writer.write("$L: options.UseAccelerate,", getExportedParameterName(parameter)); - writer.insertTrailingNewline(); - } - if (parameter.getBuiltIn().get().equals("AWS::S3::UseArnRegion")) { - writer.write("$L: options.UseARNRegion,", getExportedParameterName(parameter)); - writer.insertTrailingNewline(); - } - if (parameter.getBuiltIn().get().equals("AWS::S3::DisableMultiRegionAccessPoints")) { - writer.write("$L: options.DisableMultiRegionAccessPoints,", - getExportedParameterName(parameter)); - writer.insertTrailingNewline(); - } - if (parameter.getBuiltIn().get().equals("AWS::S3Control::UseArnRegion")) { - writer.write("$L: options.UseARNRegion,", getExportedParameterName(parameter)); - writer.insertTrailingNewline(); - } - }); + return (GoWriter writer) -> { + for(Iterator iter = parameters.iterator(); iter.hasNext();){ + Parameter parameter = iter.next(); + if (!parameter.getBuiltIn().isPresent()) { + continue; + } + if (parameter.getBuiltIn().get().equals("SDK::Endpoint")) { + writer.write("$L: options.BaseEndpoint,", getExportedParameterName(parameter)); + writer.insertTrailingNewline(); + } + if (parameter.getBuiltIn().get().equals("AWS::Region")) { + writer.write("$L: options.Region,", getExportedParameterName(parameter)); + writer.insertTrailingNewline(); + } + if (parameter.getBuiltIn().get().equals("AWS::UseFIPS")) { + writer.write("$L: options.$L.$L,", getExportedParameterName(parameter), + "EndpointOptions", USE_FIPS_ENDPOINT_OPTION); + writer.insertTrailingNewline(); + } + if (parameter.getBuiltIn().get().equals("AWS::UseDualStack")) { + writer.write("$L: options.$L.$L,", getExportedParameterName(parameter), + "EndpointOptions", DUAL_STACK_ENDPOINT_OPTION); + writer.insertTrailingNewline(); + } + if (parameter.getBuiltIn().get().equals("AWS::S3::ForcePathStyle")) { + writer.write("$L: options.UsePathStyle,", getExportedParameterName(parameter)); + writer.insertTrailingNewline(); + } + if (parameter.getBuiltIn().get().equals("AWS::S3::Accelerate")) { + writer.write("$L: options.UseAccelerate,", getExportedParameterName(parameter)); + writer.insertTrailingNewline(); + } + if (parameter.getBuiltIn().get().equals("AWS::S3::UseArnRegion")) { + writer.write("$L: options.UseARNRegion,", getExportedParameterName(parameter)); + writer.insertTrailingNewline(); + } + if (parameter.getBuiltIn().get().equals("AWS::S3::DisableMultiRegionAccessPoints")) { + writer.write("$L: options.DisableMultiRegionAccessPoints,", + getExportedParameterName(parameter)); + writer.insertTrailingNewline(); + } + if (parameter.getBuiltIn().get().equals("AWS::S3Control::UseArnRegion")) { + writer.write("$L: options.UseARNRegion,", getExportedParameterName(parameter)); + writer.insertTrailingNewline(); + } + } }; } } public static String getExportedParameterName(Parameter parameter) { - return StringUtils.capitalize(parameter.getName().asString()); + return StringUtils.capitalize(parameter.getName().getName().getValue()); } public static Symbol parameterAsSymbol(Parameter parameter) { diff --git a/codegen/smithy-aws-go-codegen/src/main/java/software/amazon/smithy/aws/go/codegen/AwsFnProvider.java b/codegen/smithy-aws-go-codegen/src/main/java/software/amazon/smithy/aws/go/codegen/AwsFnProvider.java index c8f72d400a5..ee1aee68fdc 100644 --- a/codegen/smithy-aws-go-codegen/src/main/java/software/amazon/smithy/aws/go/codegen/AwsFnProvider.java +++ b/codegen/smithy-aws-go-codegen/src/main/java/software/amazon/smithy/aws/go/codegen/AwsFnProvider.java @@ -3,8 +3,7 @@ import software.amazon.smithy.codegen.core.Symbol; import software.amazon.smithy.go.codegen.SymbolUtils; import software.amazon.smithy.go.codegen.endpoints.FnProvider; -import software.amazon.smithy.rulesengine.language.syntax.fn.FunctionDefinition; - +import software.amazon.smithy.rulesengine.language.syntax.expressions.functions.FunctionDefinition; public class AwsFnProvider implements FnProvider { @Override @@ -15,8 +14,8 @@ public Symbol fnFor(String name) { case "aws.parseArn" -> SymbolUtils.createValueSymbolBuilder("ParseARN", AwsGoDependency.AWS_ENDPOINT_RULESFN).build(); case "aws.isVirtualHostableS3Bucket" -> - SymbolUtils.createValueSymbolBuilder("IsVirtualHostableS3Bucket", - AwsGoDependency.AWS_ENDPOINT_RULESFN).build(); + SymbolUtils.createValueSymbolBuilder("IsVirtualHostableS3Bucket", + AwsGoDependency.AWS_ENDPOINT_RULESFN).build(); default -> null; }; diff --git a/codegen/smithy-aws-go-codegen/src/main/java/software/amazon/smithy/aws/go/codegen/AwsProtocolUtils.java b/codegen/smithy-aws-go-codegen/src/main/java/software/amazon/smithy/aws/go/codegen/AwsProtocolUtils.java index 5997086aed0..a6d5017114e 100644 --- a/codegen/smithy-aws-go-codegen/src/main/java/software/amazon/smithy/aws/go/codegen/AwsProtocolUtils.java +++ b/codegen/smithy-aws-go-codegen/src/main/java/software/amazon/smithy/aws/go/codegen/AwsProtocolUtils.java @@ -142,6 +142,12 @@ static void generateHttpProtocolTests(GenerationContext context) { .operation(ShapeId.from("aws.protocoltests.restxml#PutWithContentEncoding")) .addTestName("SDKAppliedContentEncoding_restXml") .addTestName("SDKAppendedGzipAfterProvidedEncoding_restXml") + .build(), + HttpProtocolUnitTestGenerator.SkipTest.builder() + .service(ShapeId.from("aws.protocoltests.restxml#RestXml")) + .operation(ShapeId.from("aws.protocoltests.restxml#HttpPayloadWithUnion")) + .addTestName("RestXmlHttpPayloadWithUnion") + .addTestName("RestXmlHttpPayloadWithUnsetUnion") .build() )); @@ -158,6 +164,22 @@ static void generateHttpProtocolTests(GenerationContext context) { .service(ShapeId.from("aws.protocoltests.restxml#RestXml")) .operation(ShapeId.from("aws.protocoltests.restxml#HttpPrefixHeaders")) .addTestName("HttpPrefixHeadersAreNotPresent") + .build(), + + HttpProtocolUnitTestGenerator.SkipTest.builder() + .service(ShapeId.from("aws.protocoltests.restjson#RestJson")) + .operation(ShapeId.from("aws.protocoltests.restjson#JsonUnions")) + .addTestName("RestJsonDeserializeIgnoreType") + .build(), + HttpProtocolUnitTestGenerator.SkipTest.builder() + .service(ShapeId.from("aws.protocoltests.json10#JsonRpc10")) + .operation(ShapeId.from("aws.protocoltests.json10#JsonUnions")) + .addTestName("AwsJson10DeserializeIgnoreType") + .build(), + HttpProtocolUnitTestGenerator.SkipTest.builder() + .service(ShapeId.from("aws.protocoltests.json#JsonProtocol")) + .operation(ShapeId.from("aws.protocoltests.json#JsonUnions")) + .addTestName("AwsJson11DeserializeIgnoreType") .build() )); diff --git a/internal/protocoltest/awsrestjson/api_op_HttpPayloadTraits.go b/internal/protocoltest/awsrestjson/api_op_HttpPayloadTraits.go index 62fa2811380..1d95e90e098 100644 --- a/internal/protocoltest/awsrestjson/api_op_HttpPayloadTraits.go +++ b/internal/protocoltest/awsrestjson/api_op_HttpPayloadTraits.go @@ -9,7 +9,7 @@ import ( smithyhttp "github.com/aws/smithy-go/transport/http" ) -// This examples serializes a blob shape in the payload. In this example, no JSON +// This example serializes a blob shape in the payload. In this example, no JSON // document is synthesized because the payload is not a structure or a union type. func (c *Client) HttpPayloadTraits(ctx context.Context, params *HttpPayloadTraitsInput, optFns ...func(*Options)) (*HttpPayloadTraitsOutput, error) { if params == nil { diff --git a/internal/protocoltest/awsrestjson/api_op_HttpPayloadTraitsWithMediaType.go b/internal/protocoltest/awsrestjson/api_op_HttpPayloadTraitsWithMediaType.go index 03236d7c771..52482ac1016 100644 --- a/internal/protocoltest/awsrestjson/api_op_HttpPayloadTraitsWithMediaType.go +++ b/internal/protocoltest/awsrestjson/api_op_HttpPayloadTraitsWithMediaType.go @@ -9,7 +9,7 @@ import ( smithyhttp "github.com/aws/smithy-go/transport/http" ) -// This examples uses a @mediaType trait on the payload to force a custom +// This example uses a @mediaType trait on the payload to force a custom // content-type to be serialized. func (c *Client) HttpPayloadTraitsWithMediaType(ctx context.Context, params *HttpPayloadTraitsWithMediaTypeInput, optFns ...func(*Options)) (*HttpPayloadTraitsWithMediaTypeOutput, error) { if params == nil { diff --git a/internal/protocoltest/awsrestjson/api_op_HttpPayloadWithStructure.go b/internal/protocoltest/awsrestjson/api_op_HttpPayloadWithStructure.go index c5c8748ccf5..4e1c8780597 100644 --- a/internal/protocoltest/awsrestjson/api_op_HttpPayloadWithStructure.go +++ b/internal/protocoltest/awsrestjson/api_op_HttpPayloadWithStructure.go @@ -10,7 +10,7 @@ import ( smithyhttp "github.com/aws/smithy-go/transport/http" ) -// This examples serializes a structure in the payload. Note that serializing a +// This example serializes a structure in the payload. Note that serializing a // structure changes the wrapper element name to match the targeted structure. func (c *Client) HttpPayloadWithStructure(ctx context.Context, params *HttpPayloadWithStructureInput, optFns ...func(*Options)) (*HttpPayloadWithStructureOutput, error) { if params == nil { diff --git a/internal/protocoltest/awsrestjson/api_op_HttpPayloadWithUnion.go b/internal/protocoltest/awsrestjson/api_op_HttpPayloadWithUnion.go new file mode 100644 index 00000000000..47d4e9e8582 --- /dev/null +++ b/internal/protocoltest/awsrestjson/api_op_HttpPayloadWithUnion.go @@ -0,0 +1,113 @@ +// Code generated by smithy-go-codegen DO NOT EDIT. + +package awsrestjson + +import ( + "context" + awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" + "github.com/aws/aws-sdk-go-v2/internal/protocoltest/awsrestjson/types" + "github.com/aws/smithy-go/middleware" + smithyhttp "github.com/aws/smithy-go/transport/http" +) + +// This example serializes a union in the payload. +func (c *Client) HttpPayloadWithUnion(ctx context.Context, params *HttpPayloadWithUnionInput, optFns ...func(*Options)) (*HttpPayloadWithUnionOutput, error) { + if params == nil { + params = &HttpPayloadWithUnionInput{} + } + + result, metadata, err := c.invokeOperation(ctx, "HttpPayloadWithUnion", params, optFns, c.addOperationHttpPayloadWithUnionMiddlewares) + if err != nil { + return nil, err + } + + out := result.(*HttpPayloadWithUnionOutput) + out.ResultMetadata = metadata + return out, nil +} + +type HttpPayloadWithUnionInput struct { + Nested types.UnionPayload + + noSmithyDocumentSerde +} + +type HttpPayloadWithUnionOutput struct { + Nested types.UnionPayload + + // Metadata pertaining to the operation's result. + ResultMetadata middleware.Metadata + + noSmithyDocumentSerde +} + +func (c *Client) addOperationHttpPayloadWithUnionMiddlewares(stack *middleware.Stack, options Options) (err error) { + err = stack.Serialize.Add(&awsRestjson1_serializeOpHttpPayloadWithUnion{}, middleware.After) + if err != nil { + return err + } + err = stack.Deserialize.Add(&awsRestjson1_deserializeOpHttpPayloadWithUnion{}, middleware.After) + if err != nil { + return err + } + if err = addlegacyEndpointContextSetter(stack, options); err != nil { + return err + } + if err = addSetLoggerMiddleware(stack, options); err != nil { + return err + } + if err = awsmiddleware.AddClientRequestIDMiddleware(stack); err != nil { + return err + } + if err = smithyhttp.AddComputeContentLengthMiddleware(stack); err != nil { + return err + } + if err = addResolveEndpointMiddleware(stack, options); err != nil { + return err + } + if err = addRetryMiddlewares(stack, options); err != nil { + return err + } + if err = awsmiddleware.AddRawResponseToMetadata(stack); err != nil { + return err + } + if err = awsmiddleware.AddRecordResponseTiming(stack); err != nil { + return err + } + if err = addClientUserAgent(stack, options); err != nil { + return err + } + if err = smithyhttp.AddErrorCloseResponseBodyMiddleware(stack); err != nil { + return err + } + if err = smithyhttp.AddCloseResponseBodyMiddleware(stack); err != nil { + return err + } + if err = stack.Initialize.Add(newServiceMetadataMiddleware_opHttpPayloadWithUnion(options.Region), middleware.Before); err != nil { + return err + } + if err = awsmiddleware.AddRecursionDetection(stack); err != nil { + return err + } + if err = addRequestIDRetrieverMiddleware(stack); err != nil { + return err + } + if err = addResponseErrorMiddleware(stack); err != nil { + return err + } + if err = addRequestResponseLogging(stack, options); err != nil { + return err + } + if err = addendpointDisableHTTPSMiddleware(stack, options); err != nil { + return err + } + return nil +} + +func newServiceMetadataMiddleware_opHttpPayloadWithUnion(region string) *awsmiddleware.RegisterServiceMetadata { + return &awsmiddleware.RegisterServiceMetadata{ + Region: region, + ServiceID: ServiceID, + OperationName: "HttpPayloadWithUnion", + } +} diff --git a/internal/protocoltest/awsrestjson/api_op_HttpPayloadWithUnion_test.go b/internal/protocoltest/awsrestjson/api_op_HttpPayloadWithUnion_test.go new file mode 100644 index 00000000000..e50d75286b8 --- /dev/null +++ b/internal/protocoltest/awsrestjson/api_op_HttpPayloadWithUnion_test.go @@ -0,0 +1,238 @@ +// Code generated by smithy-go-codegen DO NOT EDIT. + +package awsrestjson + +import ( + "bytes" + "context" + "github.com/aws/aws-sdk-go-v2/aws" + protocoltesthttp "github.com/aws/aws-sdk-go-v2/internal/protocoltest" + "github.com/aws/aws-sdk-go-v2/internal/protocoltest/awsrestjson/types" + smithydocument "github.com/aws/smithy-go/document" + "github.com/aws/smithy-go/middleware" + smithyprivateprotocol "github.com/aws/smithy-go/private/protocol" + smithyrand "github.com/aws/smithy-go/rand" + smithytesting "github.com/aws/smithy-go/testing" + smithyhttp "github.com/aws/smithy-go/transport/http" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "io" + "io/ioutil" + "math" + "net/http" + "net/url" + "testing" +) + +func TestClient_HttpPayloadWithUnion_awsRestjson1Serialize(t *testing.T) { + cases := map[string]struct { + Params *HttpPayloadWithUnionInput + ExpectMethod string + ExpectURIPath string + ExpectQuery []smithytesting.QueryItem + RequireQuery []string + ForbidQuery []string + ExpectHeader http.Header + RequireHeader []string + ForbidHeader []string + Host *url.URL + BodyMediaType string + BodyAssert func(io.Reader) error + }{ + // Serializes a union in the payload. + "RestJsonHttpPayloadWithUnion": { + Params: &HttpPayloadWithUnionInput{ + Nested: &types.UnionPayloadMemberGreeting{Value: "hello"}, + }, + ExpectMethod: "PUT", + ExpectURIPath: "/HttpPayloadWithUnion", + ExpectQuery: []smithytesting.QueryItem{}, + ExpectHeader: http.Header{ + "Content-Type": []string{"application/json"}, + }, + RequireHeader: []string{ + "Content-Length", + }, + BodyMediaType: "application/json", + BodyAssert: func(actual io.Reader) error { + return smithytesting.CompareJSONReaderBytes(actual, []byte(`{ + "greeting": "hello" + }`)) + }, + }, + // No payload is sent if the union has no value. + "RestJsonHttpPayloadWithUnsetUnion": { + Params: &HttpPayloadWithUnionInput{}, + ExpectMethod: "PUT", + ExpectURIPath: "/HttpPayloadWithUnion", + ExpectQuery: []smithytesting.QueryItem{}, + BodyAssert: func(actual io.Reader) error { + return smithytesting.CompareReaderEmpty(actual) + }, + }, + } + for name, c := range cases { + t.Run(name, func(t *testing.T) { + actualReq := &http.Request{} + serverURL := "http://localhost:8888/" + if c.Host != nil { + u, err := url.Parse(serverURL) + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + u.Path = c.Host.Path + u.RawPath = c.Host.RawPath + u.RawQuery = c.Host.RawQuery + serverURL = u.String() + } + client := New(Options{ + APIOptions: []func(*middleware.Stack) error{ + func(s *middleware.Stack) error { + s.Finalize.Clear() + s.Initialize.Remove(`OperationInputValidation`) + return nil + }, + }, + EndpointResolver: EndpointResolverFunc(func(region string, options EndpointResolverOptions) (e aws.Endpoint, err error) { + e.URL = serverURL + e.SigningRegion = "us-west-2" + return e, err + }), + HTTPClient: protocoltesthttp.NewClient(), + IdempotencyTokenProvider: smithyrand.NewUUIDIdempotencyToken(&smithytesting.ByteLoop{}), + Region: "us-west-2", + }) + result, err := client.HttpPayloadWithUnion(context.Background(), c.Params, func(options *Options) { + options.APIOptions = append(options.APIOptions, func(stack *middleware.Stack) error { + return smithyprivateprotocol.AddCaptureRequestMiddleware(stack, actualReq) + }) + }) + if err != nil { + t.Fatalf("expect nil err, got %v", err) + } + if result == nil { + t.Fatalf("expect not nil result") + } + if e, a := c.ExpectMethod, actualReq.Method; e != a { + t.Errorf("expect %v method, got %v", e, a) + } + if e, a := c.ExpectURIPath, actualReq.URL.RawPath; e != a { + t.Errorf("expect %v path, got %v", e, a) + } + queryItems := smithytesting.ParseRawQuery(actualReq.URL.RawQuery) + smithytesting.AssertHasQuery(t, c.ExpectQuery, queryItems) + smithytesting.AssertHasQueryKeys(t, c.RequireQuery, queryItems) + smithytesting.AssertNotHaveQueryKeys(t, c.ForbidQuery, queryItems) + smithytesting.AssertHasHeader(t, c.ExpectHeader, actualReq.Header) + smithytesting.AssertHasHeaderKeys(t, c.RequireHeader, actualReq.Header) + smithytesting.AssertNotHaveHeaderKeys(t, c.ForbidHeader, actualReq.Header) + if c.BodyAssert != nil { + if err := c.BodyAssert(actualReq.Body); err != nil { + t.Errorf("expect body equal, got %v", err) + } + } + }) + } +} + +func TestClient_HttpPayloadWithUnion_awsRestjson1Deserialize(t *testing.T) { + cases := map[string]struct { + StatusCode int + Header http.Header + BodyMediaType string + Body []byte + ExpectResult *HttpPayloadWithUnionOutput + }{ + // Serializes a union in the payload. + "RestJsonHttpPayloadWithUnion": { + StatusCode: 200, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + BodyMediaType: "application/json", + Body: []byte(`{ + "greeting": "hello" + }`), + ExpectResult: &HttpPayloadWithUnionOutput{ + Nested: &types.UnionPayloadMemberGreeting{Value: "hello"}, + }, + }, + // No payload is sent if the union has no value. + "RestJsonHttpPayloadWithUnsetUnion": { + StatusCode: 200, + Header: http.Header{ + "Content-Length": []string{"0"}, + }, + Body: []byte(``), + ExpectResult: &HttpPayloadWithUnionOutput{}, + }, + } + for name, c := range cases { + t.Run(name, func(t *testing.T) { + serverURL := "http://localhost:8888/" + client := New(Options{ + HTTPClient: smithyhttp.ClientDoFunc(func(r *http.Request) (*http.Response, error) { + headers := http.Header{} + for k, vs := range c.Header { + for _, v := range vs { + headers.Add(k, v) + } + } + if len(c.BodyMediaType) != 0 && len(headers.Values("Content-Type")) == 0 { + headers.Set("Content-Type", c.BodyMediaType) + } + response := &http.Response{ + StatusCode: c.StatusCode, + Header: headers, + Request: r, + } + if len(c.Body) != 0 { + response.ContentLength = int64(len(c.Body)) + response.Body = ioutil.NopCloser(bytes.NewReader(c.Body)) + } else { + + response.Body = http.NoBody + } + return response, nil + }), + APIOptions: []func(*middleware.Stack) error{ + func(s *middleware.Stack) error { + s.Finalize.Clear() + s.Initialize.Remove(`OperationInputValidation`) + return nil + }, + }, + EndpointResolver: EndpointResolverFunc(func(region string, options EndpointResolverOptions) (e aws.Endpoint, err error) { + e.URL = serverURL + e.SigningRegion = "us-west-2" + return e, err + }), + IdempotencyTokenProvider: smithyrand.NewUUIDIdempotencyToken(&smithytesting.ByteLoop{}), + Region: "us-west-2", + }) + var params HttpPayloadWithUnionInput + result, err := client.HttpPayloadWithUnion(context.Background(), ¶ms) + if err != nil { + t.Fatalf("expect nil err, got %v", err) + } + if result == nil { + t.Fatalf("expect not nil result") + } + opts := cmp.Options{ + cmpopts.IgnoreUnexported( + middleware.Metadata{}, + ), + cmp.FilterValues(func(x, y float64) bool { + return math.IsNaN(x) && math.IsNaN(y) + }, cmp.Comparer(func(_, _ interface{}) bool { return true })), + cmp.FilterValues(func(x, y float32) bool { + return math.IsNaN(float64(x)) && math.IsNaN(float64(y)) + }, cmp.Comparer(func(_, _ interface{}) bool { return true })), + cmpopts.IgnoreTypes(smithydocument.NoSerde{}), + } + if err := smithytesting.CompareValues(c.ExpectResult, result, opts...); err != nil { + t.Errorf("expect c.ExpectResult value match:\n%v", err) + } + }) + } +} diff --git a/internal/protocoltest/awsrestjson/api_op_JsonUnions_test.go b/internal/protocoltest/awsrestjson/api_op_JsonUnions_test.go index 2afa87ef00e..888e9357cb3 100644 --- a/internal/protocoltest/awsrestjson/api_op_JsonUnions_test.go +++ b/internal/protocoltest/awsrestjson/api_op_JsonUnions_test.go @@ -488,9 +488,34 @@ func TestClient_JsonUnions_awsRestjson1Deserialize(t *testing.T) { }}, }, }, + // Ignores an unrecognized __type property + "RestJsonDeserializeIgnoreType": { + StatusCode: 200, + Header: http.Header{ + "Content-Type": []string{"application/json"}, + }, + BodyMediaType: "application/json", + Body: []byte(`{ + "contents": { + "__type": "aws.protocoltests.json10#MyUnion", + "structureValue": { + "hi": "hello" + } + } + }`), + ExpectResult: &JsonUnionsOutput{ + Contents: &types.MyUnionMemberStructureValue{Value: types.GreetingStruct{ + Hi: ptr.String("hello"), + }}, + }, + }, } for name, c := range cases { t.Run(name, func(t *testing.T) { + if name == "RestJsonDeserializeIgnoreType" { + t.Skip("disabled test aws.protocoltests.restjson#RestJson aws.protocoltests.restjson#JsonUnions") + } + serverURL := "http://localhost:8888/" client := New(Options{ HTTPClient: smithyhttp.ClientDoFunc(func(r *http.Request) (*http.Response, error) { diff --git a/internal/protocoltest/awsrestjson/deserializers.go b/internal/protocoltest/awsrestjson/deserializers.go index 4893968c612..c3db515fbe1 100644 --- a/internal/protocoltest/awsrestjson/deserializers.go +++ b/internal/protocoltest/awsrestjson/deserializers.go @@ -1977,6 +1977,150 @@ func awsRestjson1_deserializeOpDocumentHttpPayloadWithStructureOutput(v **HttpPa return nil } +type awsRestjson1_deserializeOpHttpPayloadWithUnion struct { +} + +func (*awsRestjson1_deserializeOpHttpPayloadWithUnion) ID() string { + return "OperationDeserializer" +} + +func (m *awsRestjson1_deserializeOpHttpPayloadWithUnion) HandleDeserialize(ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler) ( + out middleware.DeserializeOutput, metadata middleware.Metadata, err error, +) { + out, metadata, err = next.HandleDeserialize(ctx, in) + if err != nil { + return out, metadata, err + } + + response, ok := out.RawResponse.(*smithyhttp.Response) + if !ok { + return out, metadata, &smithy.DeserializationError{Err: fmt.Errorf("unknown transport type %T", out.RawResponse)} + } + + if response.StatusCode < 200 || response.StatusCode >= 300 { + return out, metadata, awsRestjson1_deserializeOpErrorHttpPayloadWithUnion(response, &metadata) + } + output := &HttpPayloadWithUnionOutput{} + out.Result = output + + var buff [1024]byte + ringBuffer := smithyio.NewRingBuffer(buff[:]) + + body := io.TeeReader(response.Body, ringBuffer) + + decoder := json.NewDecoder(body) + decoder.UseNumber() + var shape interface{} + if err := decoder.Decode(&shape); err != nil && err != io.EOF { + var snapshot bytes.Buffer + io.Copy(&snapshot, ringBuffer) + err = &smithy.DeserializationError{ + Err: fmt.Errorf("failed to decode response body, %w", err), + Snapshot: snapshot.Bytes(), + } + return out, metadata, err + } + + err = awsRestjson1_deserializeDocumentUnionPayload(&output.Nested, shape) + if err != nil { + var snapshot bytes.Buffer + io.Copy(&snapshot, ringBuffer) + return out, metadata, &smithy.DeserializationError{ + Err: fmt.Errorf("failed to decode response body with invalid JSON, %w", err), + Snapshot: snapshot.Bytes(), + } + } + + return out, metadata, err +} + +func awsRestjson1_deserializeOpErrorHttpPayloadWithUnion(response *smithyhttp.Response, metadata *middleware.Metadata) error { + var errorBuffer bytes.Buffer + if _, err := io.Copy(&errorBuffer, response.Body); err != nil { + return &smithy.DeserializationError{Err: fmt.Errorf("failed to copy error response body, %w", err)} + } + errorBody := bytes.NewReader(errorBuffer.Bytes()) + + errorCode := "UnknownError" + errorMessage := errorCode + + headerCode := response.Header.Get("X-Amzn-ErrorType") + if len(headerCode) != 0 { + errorCode = restjson.SanitizeErrorCode(headerCode) + } + + var buff [1024]byte + ringBuffer := smithyio.NewRingBuffer(buff[:]) + + body := io.TeeReader(errorBody, ringBuffer) + decoder := json.NewDecoder(body) + decoder.UseNumber() + jsonCode, message, err := restjson.GetErrorInfo(decoder) + if err != nil { + var snapshot bytes.Buffer + io.Copy(&snapshot, ringBuffer) + err = &smithy.DeserializationError{ + Err: fmt.Errorf("failed to decode response body, %w", err), + Snapshot: snapshot.Bytes(), + } + return err + } + + errorBody.Seek(0, io.SeekStart) + if len(headerCode) == 0 && len(jsonCode) != 0 { + errorCode = restjson.SanitizeErrorCode(jsonCode) + } + if len(message) != 0 { + errorMessage = message + } + + switch { + default: + genericError := &smithy.GenericAPIError{ + Code: errorCode, + Message: errorMessage, + } + return genericError + + } +} + +func awsRestjson1_deserializeOpDocumentHttpPayloadWithUnionOutput(v **HttpPayloadWithUnionOutput, value interface{}) error { + if v == nil { + return fmt.Errorf("unexpected nil of type %T", v) + } + if value == nil { + return nil + } + + shape, ok := value.(map[string]interface{}) + if !ok { + return fmt.Errorf("unexpected JSON type %v", value) + } + + var sv *HttpPayloadWithUnionOutput + if *v == nil { + sv = &HttpPayloadWithUnionOutput{} + } else { + sv = *v + } + + for key, value := range shape { + switch key { + case "nested": + if err := awsRestjson1_deserializeDocumentUnionPayload(&sv.Nested, value); err != nil { + return err + } + + default: + _, _ = key, value + + } + } + *v = sv + return nil +} + type awsRestjson1_deserializeOpHttpPrefixHeaders struct { } @@ -11370,6 +11514,48 @@ func awsRestjson1_deserializeDocumentTestConfig(v **types.TestConfig, value inte return nil } +func awsRestjson1_deserializeDocumentUnionPayload(v *types.UnionPayload, value interface{}) error { + if v == nil { + return fmt.Errorf("unexpected nil of type %T", v) + } + if value == nil { + return nil + } + + shape, ok := value.(map[string]interface{}) + if !ok { + return fmt.Errorf("unexpected JSON type %v", value) + } + + var uv types.UnionPayload +loop: + for key, value := range shape { + if value == nil { + continue + } + switch key { + case "greeting": + var mv string + if value != nil { + jtv, ok := value.(string) + if !ok { + return fmt.Errorf("expected String to be of type string, got %T instead", value) + } + mv = jtv + } + uv = &types.UnionPayloadMemberGreeting{Value: mv} + break loop + + default: + uv = &types.UnknownUnionMember{Tag: key} + break loop + + } + } + *v = uv + return nil +} + func awsRestjson1_deserializeDocumentUnionWithJsonName(v *types.UnionWithJsonName, value interface{}) error { if v == nil { return fmt.Errorf("unexpected nil of type %T", v) diff --git a/internal/protocoltest/awsrestjson/generated.json b/internal/protocoltest/awsrestjson/generated.json index 847f654a1b3..f5c9af25d33 100644 --- a/internal/protocoltest/awsrestjson/generated.json +++ b/internal/protocoltest/awsrestjson/generated.json @@ -43,6 +43,8 @@ "api_op_HttpPayloadTraits_test.go", "api_op_HttpPayloadWithStructure.go", "api_op_HttpPayloadWithStructure_test.go", + "api_op_HttpPayloadWithUnion.go", + "api_op_HttpPayloadWithUnion_test.go", "api_op_HttpPrefixHeaders.go", "api_op_HttpPrefixHeadersInResponse.go", "api_op_HttpPrefixHeadersInResponse_test.go", diff --git a/internal/protocoltest/awsrestjson/serializers.go b/internal/protocoltest/awsrestjson/serializers.go index f7f6ee6713e..b9c9c11172f 100644 --- a/internal/protocoltest/awsrestjson/serializers.go +++ b/internal/protocoltest/awsrestjson/serializers.go @@ -1216,6 +1216,74 @@ func awsRestjson1_serializeOpHttpBindingsHttpPayloadWithStructureInput(v *HttpPa return nil } +type awsRestjson1_serializeOpHttpPayloadWithUnion struct { +} + +func (*awsRestjson1_serializeOpHttpPayloadWithUnion) ID() string { + return "OperationSerializer" +} + +func (m *awsRestjson1_serializeOpHttpPayloadWithUnion) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( + out middleware.SerializeOutput, metadata middleware.Metadata, err error, +) { + request, ok := in.Request.(*smithyhttp.Request) + if !ok { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown transport type %T", in.Request)} + } + + input, ok := in.Parameters.(*HttpPayloadWithUnionInput) + _ = input + if !ok { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown input parameters type %T", in.Parameters)} + } + + opPath, opQuery := httpbinding.SplitURI("/HttpPayloadWithUnion") + request.URL.Path = smithyhttp.JoinPath(request.URL.Path, opPath) + request.URL.RawQuery = smithyhttp.JoinRawQuery(request.URL.RawQuery, opQuery) + request.Method = "PUT" + var restEncoder *httpbinding.Encoder + if request.URL.RawPath == "" { + restEncoder, err = httpbinding.NewEncoder(request.URL.Path, request.URL.RawQuery, request.Header) + } else { + request.URL.RawPath = smithyhttp.JoinPath(request.URL.RawPath, opPath) + restEncoder, err = httpbinding.NewEncoderWithRawPath(request.URL.Path, request.URL.RawPath, request.URL.RawQuery, request.Header) + } + + if err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + + if !restEncoder.HasHeader("Content-Type") { + ctx = smithyhttp.SetIsContentTypeDefaultValue(ctx, true) + restEncoder.SetHeader("Content-Type").String("application/json") + } + + if input.Nested != nil { + jsonEncoder := smithyjson.NewEncoder() + if err := awsRestjson1_serializeDocumentUnionPayload(input.Nested, jsonEncoder.Value); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + payload := bytes.NewReader(jsonEncoder.Bytes()) + if request, err = request.SetStream(payload); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + } + + if request.Request, err = restEncoder.Encode(request.Request); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + in.Request = request + + return next.HandleSerialize(ctx, in) +} +func awsRestjson1_serializeOpHttpBindingsHttpPayloadWithUnionInput(v *HttpPayloadWithUnionInput, encoder *httpbinding.Encoder) error { + if v == nil { + return fmt.Errorf("unsupported serialization of nil %T", v) + } + + return nil +} + type awsRestjson1_serializeOpHttpPrefixHeaders struct { } @@ -7457,6 +7525,22 @@ func awsRestjson1_serializeDocumentTestConfig(v *types.TestConfig, value smithyj return nil } +func awsRestjson1_serializeDocumentUnionPayload(v types.UnionPayload, value smithyjson.Value) error { + object := value.Object() + defer object.Close() + + switch uv := v.(type) { + case *types.UnionPayloadMemberGreeting: + av := object.Key("greeting") + av.String(uv.Value) + + default: + return fmt.Errorf("attempted to serialize unknown member type %T for union %T", uv, v) + + } + return nil +} + func awsRestjson1_serializeDocumentUnionWithJsonName(v types.UnionWithJsonName, value smithyjson.Value) error { object := value.Object() defer object.Close() diff --git a/internal/protocoltest/awsrestjson/types/types.go b/internal/protocoltest/awsrestjson/types/types.go index 3961fab1b41..f53faeebe8f 100644 --- a/internal/protocoltest/awsrestjson/types/types.go +++ b/internal/protocoltest/awsrestjson/types/types.go @@ -195,6 +195,21 @@ type TestConfig struct { noSmithyDocumentSerde } +// The following types satisfy this interface: +// +// UnionPayloadMemberGreeting +type UnionPayload interface { + isUnionPayload() +} + +type UnionPayloadMemberGreeting struct { + Value string + + noSmithyDocumentSerde +} + +func (*UnionPayloadMemberGreeting) isUnionPayload() {} + // The following types satisfy this interface: // // UnionWithJsonNameMemberBar @@ -258,4 +273,5 @@ type UnknownUnionMember struct { func (*UnknownUnionMember) isMyUnion() {} func (*UnknownUnionMember) isPlayerAction() {} func (*UnknownUnionMember) isSimpleUnion() {} +func (*UnknownUnionMember) isUnionPayload() {} func (*UnknownUnionMember) isUnionWithJsonName() {} diff --git a/internal/protocoltest/awsrestjson/types/types_exported_test.go b/internal/protocoltest/awsrestjson/types/types_exported_test.go index 002794e3361..3da6bbd5b45 100644 --- a/internal/protocoltest/awsrestjson/types/types_exported_test.go +++ b/internal/protocoltest/awsrestjson/types/types_exported_test.go @@ -102,6 +102,24 @@ func ExampleSimpleUnion_outputUsage() { var _ *string var _ *int32 +func ExampleUnionPayload_outputUsage() { + var union types.UnionPayload + // type switches can be used to check the union value + switch v := union.(type) { + case *types.UnionPayloadMemberGreeting: + _ = v.Value // Value is string + + case *types.UnknownUnionMember: + fmt.Println("unknown tag:", v.Tag) + + default: + fmt.Println("union is nil or unknown type") + + } +} + +var _ *string + func ExampleUnionWithJsonName_outputUsage() { var union types.UnionWithJsonName // type switches can be used to check the union value diff --git a/internal/protocoltest/jsonrpc/api_op_JsonUnions_test.go b/internal/protocoltest/jsonrpc/api_op_JsonUnions_test.go index 5dc92d22b27..19206310da1 100644 --- a/internal/protocoltest/jsonrpc/api_op_JsonUnions_test.go +++ b/internal/protocoltest/jsonrpc/api_op_JsonUnions_test.go @@ -471,9 +471,34 @@ func TestClient_JsonUnions_awsAwsjson11Deserialize(t *testing.T) { }}, }, }, + // Ignores an unrecognized __type property + "AwsJson11DeserializeIgnoreType": { + StatusCode: 200, + Header: http.Header{ + "Content-Type": []string{"application/x-amz-json-1.1"}, + }, + BodyMediaType: "application/json", + Body: []byte(`{ + "contents": { + "__type": "aws.protocoltests.json10#MyUnion", + "structureValue": { + "hi": "hello" + } + } + }`), + ExpectResult: &JsonUnionsOutput{ + Contents: &types.MyUnionMemberStructureValue{Value: types.GreetingStruct{ + Hi: ptr.String("hello"), + }}, + }, + }, } for name, c := range cases { t.Run(name, func(t *testing.T) { + if name == "AwsJson11DeserializeIgnoreType" { + t.Skip("disabled test aws.protocoltests.json#JsonProtocol aws.protocoltests.json#JsonUnions") + } + serverURL := "http://localhost:8888/" client := New(Options{ HTTPClient: smithyhttp.ClientDoFunc(func(r *http.Request) (*http.Response, error) { diff --git a/internal/protocoltest/jsonrpc10/api_op_JsonUnions_test.go b/internal/protocoltest/jsonrpc10/api_op_JsonUnions_test.go index 2dad560b404..844b2408c54 100644 --- a/internal/protocoltest/jsonrpc10/api_op_JsonUnions_test.go +++ b/internal/protocoltest/jsonrpc10/api_op_JsonUnions_test.go @@ -508,9 +508,34 @@ func TestClient_JsonUnions_awsAwsjson10Deserialize(t *testing.T) { }}, }, }, + // Ignores an unrecognized __type property + "AwsJson10DeserializeIgnoreType": { + StatusCode: 200, + Header: http.Header{ + "Content-Type": []string{"application/x-amz-json-1.0"}, + }, + BodyMediaType: "application/json", + Body: []byte(`{ + "contents": { + "__type": "aws.protocoltests.json10#MyUnion", + "structureValue": { + "hi": "hello" + } + } + }`), + ExpectResult: &JsonUnionsOutput{ + Contents: &types.MyUnionMemberStructureValue{Value: types.GreetingStruct{ + Hi: ptr.String("hello"), + }}, + }, + }, } for name, c := range cases { t.Run(name, func(t *testing.T) { + if name == "AwsJson10DeserializeIgnoreType" { + t.Skip("disabled test aws.protocoltests.json10#JsonRpc10 aws.protocoltests.json10#JsonUnions") + } + serverURL := "http://localhost:8888/" client := New(Options{ HTTPClient: smithyhttp.ClientDoFunc(func(r *http.Request) (*http.Response, error) { diff --git a/internal/protocoltest/restxml/api_op_HttpPayloadTraits.go b/internal/protocoltest/restxml/api_op_HttpPayloadTraits.go index 28adc357dc6..8fb6a04a649 100644 --- a/internal/protocoltest/restxml/api_op_HttpPayloadTraits.go +++ b/internal/protocoltest/restxml/api_op_HttpPayloadTraits.go @@ -9,7 +9,7 @@ import ( smithyhttp "github.com/aws/smithy-go/transport/http" ) -// This examples serializes a blob shape in the payload. In this example, no XML +// This example serializes a blob shape in the payload. In this example, no XML // document is synthesized because the payload is not a structure or a union type. func (c *Client) HttpPayloadTraits(ctx context.Context, params *HttpPayloadTraitsInput, optFns ...func(*Options)) (*HttpPayloadTraitsOutput, error) { if params == nil { diff --git a/internal/protocoltest/restxml/api_op_HttpPayloadTraitsWithMediaType.go b/internal/protocoltest/restxml/api_op_HttpPayloadTraitsWithMediaType.go index dd67e879523..6b46af7a304 100644 --- a/internal/protocoltest/restxml/api_op_HttpPayloadTraitsWithMediaType.go +++ b/internal/protocoltest/restxml/api_op_HttpPayloadTraitsWithMediaType.go @@ -9,7 +9,7 @@ import ( smithyhttp "github.com/aws/smithy-go/transport/http" ) -// This examples uses a @mediaType trait on the payload to force a custom +// This example uses a @mediaType trait on the payload to force a custom // content-type to be serialized. func (c *Client) HttpPayloadTraitsWithMediaType(ctx context.Context, params *HttpPayloadTraitsWithMediaTypeInput, optFns ...func(*Options)) (*HttpPayloadTraitsWithMediaTypeOutput, error) { if params == nil { diff --git a/internal/protocoltest/restxml/api_op_HttpPayloadWithStructure.go b/internal/protocoltest/restxml/api_op_HttpPayloadWithStructure.go index ed05a8be430..1c8bbeb5eb1 100644 --- a/internal/protocoltest/restxml/api_op_HttpPayloadWithStructure.go +++ b/internal/protocoltest/restxml/api_op_HttpPayloadWithStructure.go @@ -10,7 +10,7 @@ import ( smithyhttp "github.com/aws/smithy-go/transport/http" ) -// This examples serializes a structure in the payload. Note that serializing a +// This example serializes a structure in the payload. Note that serializing a // structure changes the wrapper element name to match the targeted structure. func (c *Client) HttpPayloadWithStructure(ctx context.Context, params *HttpPayloadWithStructureInput, optFns ...func(*Options)) (*HttpPayloadWithStructureOutput, error) { if params == nil { diff --git a/internal/protocoltest/restxml/api_op_HttpPayloadWithUnion.go b/internal/protocoltest/restxml/api_op_HttpPayloadWithUnion.go new file mode 100644 index 00000000000..c8a494ceb20 --- /dev/null +++ b/internal/protocoltest/restxml/api_op_HttpPayloadWithUnion.go @@ -0,0 +1,113 @@ +// Code generated by smithy-go-codegen DO NOT EDIT. + +package restxml + +import ( + "context" + awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" + "github.com/aws/aws-sdk-go-v2/internal/protocoltest/restxml/types" + "github.com/aws/smithy-go/middleware" + smithyhttp "github.com/aws/smithy-go/transport/http" +) + +// This example serializes a union in the payload. +func (c *Client) HttpPayloadWithUnion(ctx context.Context, params *HttpPayloadWithUnionInput, optFns ...func(*Options)) (*HttpPayloadWithUnionOutput, error) { + if params == nil { + params = &HttpPayloadWithUnionInput{} + } + + result, metadata, err := c.invokeOperation(ctx, "HttpPayloadWithUnion", params, optFns, c.addOperationHttpPayloadWithUnionMiddlewares) + if err != nil { + return nil, err + } + + out := result.(*HttpPayloadWithUnionOutput) + out.ResultMetadata = metadata + return out, nil +} + +type HttpPayloadWithUnionInput struct { + Nested types.UnionPayload + + noSmithyDocumentSerde +} + +type HttpPayloadWithUnionOutput struct { + Nested types.UnionPayload + + // Metadata pertaining to the operation's result. + ResultMetadata middleware.Metadata + + noSmithyDocumentSerde +} + +func (c *Client) addOperationHttpPayloadWithUnionMiddlewares(stack *middleware.Stack, options Options) (err error) { + err = stack.Serialize.Add(&awsRestxml_serializeOpHttpPayloadWithUnion{}, middleware.After) + if err != nil { + return err + } + err = stack.Deserialize.Add(&awsRestxml_deserializeOpHttpPayloadWithUnion{}, middleware.After) + if err != nil { + return err + } + if err = addlegacyEndpointContextSetter(stack, options); err != nil { + return err + } + if err = addSetLoggerMiddleware(stack, options); err != nil { + return err + } + if err = awsmiddleware.AddClientRequestIDMiddleware(stack); err != nil { + return err + } + if err = smithyhttp.AddComputeContentLengthMiddleware(stack); err != nil { + return err + } + if err = addResolveEndpointMiddleware(stack, options); err != nil { + return err + } + if err = addRetryMiddlewares(stack, options); err != nil { + return err + } + if err = awsmiddleware.AddRawResponseToMetadata(stack); err != nil { + return err + } + if err = awsmiddleware.AddRecordResponseTiming(stack); err != nil { + return err + } + if err = addClientUserAgent(stack, options); err != nil { + return err + } + if err = smithyhttp.AddErrorCloseResponseBodyMiddleware(stack); err != nil { + return err + } + if err = smithyhttp.AddCloseResponseBodyMiddleware(stack); err != nil { + return err + } + if err = stack.Initialize.Add(newServiceMetadataMiddleware_opHttpPayloadWithUnion(options.Region), middleware.Before); err != nil { + return err + } + if err = awsmiddleware.AddRecursionDetection(stack); err != nil { + return err + } + if err = addRequestIDRetrieverMiddleware(stack); err != nil { + return err + } + if err = addResponseErrorMiddleware(stack); err != nil { + return err + } + if err = addRequestResponseLogging(stack, options); err != nil { + return err + } + if err = addendpointDisableHTTPSMiddleware(stack, options); err != nil { + return err + } + return nil +} + +func newServiceMetadataMiddleware_opHttpPayloadWithUnion(region string) *awsmiddleware.RegisterServiceMetadata { + return &awsmiddleware.RegisterServiceMetadata{ + Region: region, + ServiceID: ServiceID, + OperationName: "HttpPayloadWithUnion", + } +} diff --git a/internal/protocoltest/restxml/api_op_HttpPayloadWithUnion_test.go b/internal/protocoltest/restxml/api_op_HttpPayloadWithUnion_test.go new file mode 100644 index 00000000000..5bf002cd49c --- /dev/null +++ b/internal/protocoltest/restxml/api_op_HttpPayloadWithUnion_test.go @@ -0,0 +1,249 @@ +// Code generated by smithy-go-codegen DO NOT EDIT. + +package restxml + +import ( + "bytes" + "context" + "github.com/aws/aws-sdk-go-v2/aws" + protocoltesthttp "github.com/aws/aws-sdk-go-v2/internal/protocoltest" + "github.com/aws/aws-sdk-go-v2/internal/protocoltest/restxml/types" + smithydocument "github.com/aws/smithy-go/document" + "github.com/aws/smithy-go/middleware" + smithyprivateprotocol "github.com/aws/smithy-go/private/protocol" + smithyrand "github.com/aws/smithy-go/rand" + smithytesting "github.com/aws/smithy-go/testing" + smithyhttp "github.com/aws/smithy-go/transport/http" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "io" + "io/ioutil" + "math" + "net/http" + "net/url" + "testing" +) + +func TestClient_HttpPayloadWithUnion_awsRestxmlSerialize(t *testing.T) { + cases := map[string]struct { + Params *HttpPayloadWithUnionInput + ExpectMethod string + ExpectURIPath string + ExpectQuery []smithytesting.QueryItem + RequireQuery []string + ForbidQuery []string + ExpectHeader http.Header + RequireHeader []string + ForbidHeader []string + Host *url.URL + BodyMediaType string + BodyAssert func(io.Reader) error + }{ + // Serializes a union in the payload. + "RestXmlHttpPayloadWithUnion": { + Params: &HttpPayloadWithUnionInput{ + Nested: &types.UnionPayloadMemberGreeting{Value: "hello"}, + }, + ExpectMethod: "PUT", + ExpectURIPath: "/HttpPayloadWithUnion", + ExpectQuery: []smithytesting.QueryItem{}, + ExpectHeader: http.Header{ + "Content-Type": []string{"application/xml"}, + }, + RequireHeader: []string{ + "Content-Length", + }, + BodyMediaType: "application/xml", + BodyAssert: func(actual io.Reader) error { + return smithytesting.CompareXMLReaderBytes(actual, []byte(` + hello + `)) + }, + }, + // No payload is sent if the union has no value. + "RestXmlHttpPayloadWithUnsetUnion": { + Params: &HttpPayloadWithUnionInput{}, + ExpectMethod: "PUT", + ExpectURIPath: "/HttpPayloadWithUnion", + ExpectQuery: []smithytesting.QueryItem{}, + ExpectHeader: http.Header{ + "Content-Type": []string{"application/xml"}, + }, + BodyAssert: func(actual io.Reader) error { + return smithytesting.CompareReaderEmpty(actual) + }, + }, + } + for name, c := range cases { + t.Run(name, func(t *testing.T) { + if name == "RestXmlHttpPayloadWithUnion" { + t.Skip("disabled test aws.protocoltests.restxml#RestXml aws.protocoltests.restxml#HttpPayloadWithUnion") + } + + if name == "RestXmlHttpPayloadWithUnsetUnion" { + t.Skip("disabled test aws.protocoltests.restxml#RestXml aws.protocoltests.restxml#HttpPayloadWithUnion") + } + + actualReq := &http.Request{} + serverURL := "http://localhost:8888/" + if c.Host != nil { + u, err := url.Parse(serverURL) + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + u.Path = c.Host.Path + u.RawPath = c.Host.RawPath + u.RawQuery = c.Host.RawQuery + serverURL = u.String() + } + client := New(Options{ + APIOptions: []func(*middleware.Stack) error{ + func(s *middleware.Stack) error { + s.Finalize.Clear() + s.Initialize.Remove(`OperationInputValidation`) + return nil + }, + }, + EndpointResolver: EndpointResolverFunc(func(region string, options EndpointResolverOptions) (e aws.Endpoint, err error) { + e.URL = serverURL + e.SigningRegion = "us-west-2" + return e, err + }), + HTTPClient: protocoltesthttp.NewClient(), + IdempotencyTokenProvider: smithyrand.NewUUIDIdempotencyToken(&smithytesting.ByteLoop{}), + Region: "us-west-2", + }) + result, err := client.HttpPayloadWithUnion(context.Background(), c.Params, func(options *Options) { + options.APIOptions = append(options.APIOptions, func(stack *middleware.Stack) error { + return smithyprivateprotocol.AddCaptureRequestMiddleware(stack, actualReq) + }) + }) + if err != nil { + t.Fatalf("expect nil err, got %v", err) + } + if result == nil { + t.Fatalf("expect not nil result") + } + if e, a := c.ExpectMethod, actualReq.Method; e != a { + t.Errorf("expect %v method, got %v", e, a) + } + if e, a := c.ExpectURIPath, actualReq.URL.RawPath; e != a { + t.Errorf("expect %v path, got %v", e, a) + } + queryItems := smithytesting.ParseRawQuery(actualReq.URL.RawQuery) + smithytesting.AssertHasQuery(t, c.ExpectQuery, queryItems) + smithytesting.AssertHasQueryKeys(t, c.RequireQuery, queryItems) + smithytesting.AssertNotHaveQueryKeys(t, c.ForbidQuery, queryItems) + smithytesting.AssertHasHeader(t, c.ExpectHeader, actualReq.Header) + smithytesting.AssertHasHeaderKeys(t, c.RequireHeader, actualReq.Header) + smithytesting.AssertNotHaveHeaderKeys(t, c.ForbidHeader, actualReq.Header) + if c.BodyAssert != nil { + if err := c.BodyAssert(actualReq.Body); err != nil { + t.Errorf("expect body equal, got %v", err) + } + } + }) + } +} + +func TestClient_HttpPayloadWithUnion_awsRestxmlDeserialize(t *testing.T) { + cases := map[string]struct { + StatusCode int + Header http.Header + BodyMediaType string + Body []byte + ExpectResult *HttpPayloadWithUnionOutput + }{ + // Serializes a union in the payload. + "RestXmlHttpPayloadWithUnion": { + StatusCode: 200, + Header: http.Header{ + "Content-Type": []string{"application/xml"}, + }, + BodyMediaType: "application/xml", + Body: []byte(` + hello + `), + ExpectResult: &HttpPayloadWithUnionOutput{ + Nested: &types.UnionPayloadMemberGreeting{Value: "hello"}, + }, + }, + // No payload is sent if the union has no value. + "RestXmlHttpPayloadWithUnsetUnion": { + StatusCode: 200, + Header: http.Header{ + "Content-Length": []string{"0"}, + }, + Body: []byte(``), + ExpectResult: &HttpPayloadWithUnionOutput{}, + }, + } + for name, c := range cases { + t.Run(name, func(t *testing.T) { + serverURL := "http://localhost:8888/" + client := New(Options{ + HTTPClient: smithyhttp.ClientDoFunc(func(r *http.Request) (*http.Response, error) { + headers := http.Header{} + for k, vs := range c.Header { + for _, v := range vs { + headers.Add(k, v) + } + } + if len(c.BodyMediaType) != 0 && len(headers.Values("Content-Type")) == 0 { + headers.Set("Content-Type", c.BodyMediaType) + } + response := &http.Response{ + StatusCode: c.StatusCode, + Header: headers, + Request: r, + } + if len(c.Body) != 0 { + response.ContentLength = int64(len(c.Body)) + response.Body = ioutil.NopCloser(bytes.NewReader(c.Body)) + } else { + + response.Body = http.NoBody + } + return response, nil + }), + APIOptions: []func(*middleware.Stack) error{ + func(s *middleware.Stack) error { + s.Finalize.Clear() + s.Initialize.Remove(`OperationInputValidation`) + return nil + }, + }, + EndpointResolver: EndpointResolverFunc(func(region string, options EndpointResolverOptions) (e aws.Endpoint, err error) { + e.URL = serverURL + e.SigningRegion = "us-west-2" + return e, err + }), + IdempotencyTokenProvider: smithyrand.NewUUIDIdempotencyToken(&smithytesting.ByteLoop{}), + Region: "us-west-2", + }) + var params HttpPayloadWithUnionInput + result, err := client.HttpPayloadWithUnion(context.Background(), ¶ms) + if err != nil { + t.Fatalf("expect nil err, got %v", err) + } + if result == nil { + t.Fatalf("expect not nil result") + } + opts := cmp.Options{ + cmpopts.IgnoreUnexported( + middleware.Metadata{}, + ), + cmp.FilterValues(func(x, y float64) bool { + return math.IsNaN(x) && math.IsNaN(y) + }, cmp.Comparer(func(_, _ interface{}) bool { return true })), + cmp.FilterValues(func(x, y float32) bool { + return math.IsNaN(float64(x)) && math.IsNaN(float64(y)) + }, cmp.Comparer(func(_, _ interface{}) bool { return true })), + cmpopts.IgnoreTypes(smithydocument.NoSerde{}), + } + if err := smithytesting.CompareValues(c.ExpectResult, result, opts...); err != nil { + t.Errorf("expect c.ExpectResult value match:\n%v", err) + } + }) + } +} diff --git a/internal/protocoltest/restxml/api_op_XmlMapWithXmlNamespace.go b/internal/protocoltest/restxml/api_op_XmlMapWithXmlNamespace.go new file mode 100644 index 00000000000..92fa6aa8bad --- /dev/null +++ b/internal/protocoltest/restxml/api_op_XmlMapWithXmlNamespace.go @@ -0,0 +1,112 @@ +// Code generated by smithy-go-codegen DO NOT EDIT. + +package restxml + +import ( + "context" + awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" + "github.com/aws/smithy-go/middleware" + smithyhttp "github.com/aws/smithy-go/transport/http" +) + +// Maps with @xmlNamespace and @xmlName +func (c *Client) XmlMapWithXmlNamespace(ctx context.Context, params *XmlMapWithXmlNamespaceInput, optFns ...func(*Options)) (*XmlMapWithXmlNamespaceOutput, error) { + if params == nil { + params = &XmlMapWithXmlNamespaceInput{} + } + + result, metadata, err := c.invokeOperation(ctx, "XmlMapWithXmlNamespace", params, optFns, c.addOperationXmlMapWithXmlNamespaceMiddlewares) + if err != nil { + return nil, err + } + + out := result.(*XmlMapWithXmlNamespaceOutput) + out.ResultMetadata = metadata + return out, nil +} + +type XmlMapWithXmlNamespaceInput struct { + MyMap map[string]string + + noSmithyDocumentSerde +} + +type XmlMapWithXmlNamespaceOutput struct { + MyMap map[string]string + + // Metadata pertaining to the operation's result. + ResultMetadata middleware.Metadata + + noSmithyDocumentSerde +} + +func (c *Client) addOperationXmlMapWithXmlNamespaceMiddlewares(stack *middleware.Stack, options Options) (err error) { + err = stack.Serialize.Add(&awsRestxml_serializeOpXmlMapWithXmlNamespace{}, middleware.After) + if err != nil { + return err + } + err = stack.Deserialize.Add(&awsRestxml_deserializeOpXmlMapWithXmlNamespace{}, middleware.After) + if err != nil { + return err + } + if err = addlegacyEndpointContextSetter(stack, options); err != nil { + return err + } + if err = addSetLoggerMiddleware(stack, options); err != nil { + return err + } + if err = awsmiddleware.AddClientRequestIDMiddleware(stack); err != nil { + return err + } + if err = smithyhttp.AddComputeContentLengthMiddleware(stack); err != nil { + return err + } + if err = addResolveEndpointMiddleware(stack, options); err != nil { + return err + } + if err = addRetryMiddlewares(stack, options); err != nil { + return err + } + if err = awsmiddleware.AddRawResponseToMetadata(stack); err != nil { + return err + } + if err = awsmiddleware.AddRecordResponseTiming(stack); err != nil { + return err + } + if err = addClientUserAgent(stack, options); err != nil { + return err + } + if err = smithyhttp.AddErrorCloseResponseBodyMiddleware(stack); err != nil { + return err + } + if err = smithyhttp.AddCloseResponseBodyMiddleware(stack); err != nil { + return err + } + if err = stack.Initialize.Add(newServiceMetadataMiddleware_opXmlMapWithXmlNamespace(options.Region), middleware.Before); err != nil { + return err + } + if err = awsmiddleware.AddRecursionDetection(stack); err != nil { + return err + } + if err = addRequestIDRetrieverMiddleware(stack); err != nil { + return err + } + if err = addResponseErrorMiddleware(stack); err != nil { + return err + } + if err = addRequestResponseLogging(stack, options); err != nil { + return err + } + if err = addendpointDisableHTTPSMiddleware(stack, options); err != nil { + return err + } + return nil +} + +func newServiceMetadataMiddleware_opXmlMapWithXmlNamespace(region string) *awsmiddleware.RegisterServiceMetadata { + return &awsmiddleware.RegisterServiceMetadata{ + Region: region, + ServiceID: ServiceID, + OperationName: "XmlMapWithXmlNamespace", + } +} diff --git a/internal/protocoltest/restxml/api_op_XmlMapWithXmlNamespace_test.go b/internal/protocoltest/restxml/api_op_XmlMapWithXmlNamespace_test.go new file mode 100644 index 00000000000..9fbb633e486 --- /dev/null +++ b/internal/protocoltest/restxml/api_op_XmlMapWithXmlNamespace_test.go @@ -0,0 +1,239 @@ +// Code generated by smithy-go-codegen DO NOT EDIT. + +package restxml + +import ( + "bytes" + "context" + "github.com/aws/aws-sdk-go-v2/aws" + protocoltesthttp "github.com/aws/aws-sdk-go-v2/internal/protocoltest" + smithydocument "github.com/aws/smithy-go/document" + "github.com/aws/smithy-go/middleware" + smithyprivateprotocol "github.com/aws/smithy-go/private/protocol" + smithyrand "github.com/aws/smithy-go/rand" + smithytesting "github.com/aws/smithy-go/testing" + smithyhttp "github.com/aws/smithy-go/transport/http" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "io" + "io/ioutil" + "math" + "net/http" + "net/url" + "testing" +) + +func TestClient_XmlMapWithXmlNamespace_awsRestxmlSerialize(t *testing.T) { + cases := map[string]struct { + Params *XmlMapWithXmlNamespaceInput + ExpectMethod string + ExpectURIPath string + ExpectQuery []smithytesting.QueryItem + RequireQuery []string + ForbidQuery []string + ExpectHeader http.Header + RequireHeader []string + ForbidHeader []string + Host *url.URL + BodyMediaType string + BodyAssert func(io.Reader) error + }{ + // Serializes XML maps in requests that have xmlNamespace and xmlName on members + "RestXmlXmlMapWithXmlNamespace": { + Params: &XmlMapWithXmlNamespaceInput{ + MyMap: map[string]string{ + "a": "A", + "b": "B", + }, + }, + ExpectMethod: "POST", + ExpectURIPath: "/XmlMapWithXmlNamespace", + ExpectQuery: []smithytesting.QueryItem{}, + ExpectHeader: http.Header{ + "Content-Type": []string{"application/xml"}, + }, + BodyMediaType: "application/xml", + BodyAssert: func(actual io.Reader) error { + return smithytesting.CompareXMLReaderBytes(actual, []byte(` + + + a + A + + + b + B + + + `)) + }, + }, + } + for name, c := range cases { + t.Run(name, func(t *testing.T) { + actualReq := &http.Request{} + serverURL := "http://localhost:8888/" + if c.Host != nil { + u, err := url.Parse(serverURL) + if err != nil { + t.Fatalf("expect no error, got %v", err) + } + u.Path = c.Host.Path + u.RawPath = c.Host.RawPath + u.RawQuery = c.Host.RawQuery + serverURL = u.String() + } + client := New(Options{ + APIOptions: []func(*middleware.Stack) error{ + func(s *middleware.Stack) error { + s.Finalize.Clear() + s.Initialize.Remove(`OperationInputValidation`) + return nil + }, + }, + EndpointResolver: EndpointResolverFunc(func(region string, options EndpointResolverOptions) (e aws.Endpoint, err error) { + e.URL = serverURL + e.SigningRegion = "us-west-2" + return e, err + }), + HTTPClient: protocoltesthttp.NewClient(), + IdempotencyTokenProvider: smithyrand.NewUUIDIdempotencyToken(&smithytesting.ByteLoop{}), + Region: "us-west-2", + }) + result, err := client.XmlMapWithXmlNamespace(context.Background(), c.Params, func(options *Options) { + options.APIOptions = append(options.APIOptions, func(stack *middleware.Stack) error { + return smithyprivateprotocol.AddCaptureRequestMiddleware(stack, actualReq) + }) + }) + if err != nil { + t.Fatalf("expect nil err, got %v", err) + } + if result == nil { + t.Fatalf("expect not nil result") + } + if e, a := c.ExpectMethod, actualReq.Method; e != a { + t.Errorf("expect %v method, got %v", e, a) + } + if e, a := c.ExpectURIPath, actualReq.URL.RawPath; e != a { + t.Errorf("expect %v path, got %v", e, a) + } + queryItems := smithytesting.ParseRawQuery(actualReq.URL.RawQuery) + smithytesting.AssertHasQuery(t, c.ExpectQuery, queryItems) + smithytesting.AssertHasQueryKeys(t, c.RequireQuery, queryItems) + smithytesting.AssertNotHaveQueryKeys(t, c.ForbidQuery, queryItems) + smithytesting.AssertHasHeader(t, c.ExpectHeader, actualReq.Header) + smithytesting.AssertHasHeaderKeys(t, c.RequireHeader, actualReq.Header) + smithytesting.AssertNotHaveHeaderKeys(t, c.ForbidHeader, actualReq.Header) + if c.BodyAssert != nil { + if err := c.BodyAssert(actualReq.Body); err != nil { + t.Errorf("expect body equal, got %v", err) + } + } + }) + } +} + +func TestClient_XmlMapWithXmlNamespace_awsRestxmlDeserialize(t *testing.T) { + cases := map[string]struct { + StatusCode int + Header http.Header + BodyMediaType string + Body []byte + ExpectResult *XmlMapWithXmlNamespaceOutput + }{ + // Serializes XML maps in responses that have xmlNamespace and xmlName on members + "RestXmlXmlMapWithXmlNamespace": { + StatusCode: 200, + Header: http.Header{ + "Content-Type": []string{"application/xml"}, + }, + BodyMediaType: "application/xml", + Body: []byte(` + + + a + A + + + b + B + + + `), + ExpectResult: &XmlMapWithXmlNamespaceOutput{ + MyMap: map[string]string{ + "a": "A", + "b": "B", + }, + }, + }, + } + for name, c := range cases { + t.Run(name, func(t *testing.T) { + serverURL := "http://localhost:8888/" + client := New(Options{ + HTTPClient: smithyhttp.ClientDoFunc(func(r *http.Request) (*http.Response, error) { + headers := http.Header{} + for k, vs := range c.Header { + for _, v := range vs { + headers.Add(k, v) + } + } + if len(c.BodyMediaType) != 0 && len(headers.Values("Content-Type")) == 0 { + headers.Set("Content-Type", c.BodyMediaType) + } + response := &http.Response{ + StatusCode: c.StatusCode, + Header: headers, + Request: r, + } + if len(c.Body) != 0 { + response.ContentLength = int64(len(c.Body)) + response.Body = ioutil.NopCloser(bytes.NewReader(c.Body)) + } else { + + response.Body = http.NoBody + } + return response, nil + }), + APIOptions: []func(*middleware.Stack) error{ + func(s *middleware.Stack) error { + s.Finalize.Clear() + s.Initialize.Remove(`OperationInputValidation`) + return nil + }, + }, + EndpointResolver: EndpointResolverFunc(func(region string, options EndpointResolverOptions) (e aws.Endpoint, err error) { + e.URL = serverURL + e.SigningRegion = "us-west-2" + return e, err + }), + IdempotencyTokenProvider: smithyrand.NewUUIDIdempotencyToken(&smithytesting.ByteLoop{}), + Region: "us-west-2", + }) + var params XmlMapWithXmlNamespaceInput + result, err := client.XmlMapWithXmlNamespace(context.Background(), ¶ms) + if err != nil { + t.Fatalf("expect nil err, got %v", err) + } + if result == nil { + t.Fatalf("expect not nil result") + } + opts := cmp.Options{ + cmpopts.IgnoreUnexported( + middleware.Metadata{}, + ), + cmp.FilterValues(func(x, y float64) bool { + return math.IsNaN(x) && math.IsNaN(y) + }, cmp.Comparer(func(_, _ interface{}) bool { return true })), + cmp.FilterValues(func(x, y float32) bool { + return math.IsNaN(float64(x)) && math.IsNaN(float64(y)) + }, cmp.Comparer(func(_, _ interface{}) bool { return true })), + cmpopts.IgnoreTypes(smithydocument.NoSerde{}), + } + if err := smithytesting.CompareValues(c.ExpectResult, result, opts...); err != nil { + t.Errorf("expect c.ExpectResult value match:\n%v", err) + } + }) + } +} diff --git a/internal/protocoltest/restxml/deserializers.go b/internal/protocoltest/restxml/deserializers.go index 2bbe50e30b8..1b29d7b6128 100644 --- a/internal/protocoltest/restxml/deserializers.go +++ b/internal/protocoltest/restxml/deserializers.go @@ -1905,6 +1905,140 @@ func awsRestxml_deserializeOpDocumentHttpPayloadWithStructureOutput(v **HttpPayl return nil } +type awsRestxml_deserializeOpHttpPayloadWithUnion struct { +} + +func (*awsRestxml_deserializeOpHttpPayloadWithUnion) ID() string { + return "OperationDeserializer" +} + +func (m *awsRestxml_deserializeOpHttpPayloadWithUnion) HandleDeserialize(ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler) ( + out middleware.DeserializeOutput, metadata middleware.Metadata, err error, +) { + out, metadata, err = next.HandleDeserialize(ctx, in) + if err != nil { + return out, metadata, err + } + + response, ok := out.RawResponse.(*smithyhttp.Response) + if !ok { + return out, metadata, &smithy.DeserializationError{Err: fmt.Errorf("unknown transport type %T", out.RawResponse)} + } + + if response.StatusCode < 200 || response.StatusCode >= 300 { + return out, metadata, awsRestxml_deserializeOpErrorHttpPayloadWithUnion(response, &metadata) + } + output := &HttpPayloadWithUnionOutput{} + out.Result = output + + var buff [1024]byte + ringBuffer := smithyio.NewRingBuffer(buff[:]) + body := io.TeeReader(response.Body, ringBuffer) + rootDecoder := xml.NewDecoder(body) + t, err := smithyxml.FetchRootElement(rootDecoder) + if err == io.EOF { + return out, metadata, nil + } + if err != nil { + var snapshot bytes.Buffer + io.Copy(&snapshot, ringBuffer) + return out, metadata, &smithy.DeserializationError{ + Err: fmt.Errorf("failed to decode response body, %w", err), + Snapshot: snapshot.Bytes(), + } + } + + decoder := smithyxml.WrapNodeDecoder(rootDecoder, t) + err = awsRestxml_deserializeDocumentUnionPayload(&output.Nested, decoder) + if err != nil { + var snapshot bytes.Buffer + io.Copy(&snapshot, ringBuffer) + return out, metadata, &smithy.DeserializationError{ + Err: fmt.Errorf("failed to decode response body, %w", err), + Snapshot: snapshot.Bytes(), + } + } + + return out, metadata, err +} + +func awsRestxml_deserializeOpErrorHttpPayloadWithUnion(response *smithyhttp.Response, metadata *middleware.Metadata) error { + var errorBuffer bytes.Buffer + if _, err := io.Copy(&errorBuffer, response.Body); err != nil { + return &smithy.DeserializationError{Err: fmt.Errorf("failed to copy error response body, %w", err)} + } + errorBody := bytes.NewReader(errorBuffer.Bytes()) + + errorCode := "UnknownError" + errorMessage := errorCode + + errorComponents, err := awsxml.GetErrorResponseComponents(errorBody, false) + if err != nil { + return err + } + if reqID := errorComponents.RequestID; len(reqID) != 0 { + awsmiddleware.SetRequestIDMetadata(metadata, reqID) + } + if len(errorComponents.Code) != 0 { + errorCode = errorComponents.Code + } + if len(errorComponents.Message) != 0 { + errorMessage = errorComponents.Message + } + errorBody.Seek(0, io.SeekStart) + switch { + default: + genericError := &smithy.GenericAPIError{ + Code: errorCode, + Message: errorMessage, + } + return genericError + + } +} + +func awsRestxml_deserializeOpDocumentHttpPayloadWithUnionOutput(v **HttpPayloadWithUnionOutput, decoder smithyxml.NodeDecoder) error { + if v == nil { + return fmt.Errorf("unexpected nil of type %T", v) + } + var sv *HttpPayloadWithUnionOutput + if *v == nil { + sv = &HttpPayloadWithUnionOutput{} + } else { + sv = *v + } + + for { + t, done, err := decoder.Token() + if err != nil { + return err + } + if done { + break + } + originalDecoder := decoder + decoder = smithyxml.WrapNodeDecoder(originalDecoder.Decoder, t) + switch { + case strings.EqualFold("nested", t.Name.Local): + nodeDecoder := smithyxml.WrapNodeDecoder(decoder.Decoder, t) + if err := awsRestxml_deserializeDocumentUnionPayload(&sv.Nested, nodeDecoder); err != nil { + return err + } + + default: + // Do nothing and ignore the unexpected tag element + err = decoder.Decoder.Skip() + if err != nil { + return err + } + + } + decoder = originalDecoder + } + *v = sv + return nil +} + type awsRestxml_deserializeOpHttpPayloadWithXmlName struct { } @@ -6507,6 +6641,140 @@ func awsRestxml_deserializeOpDocumentXmlMapsXmlNameOutput(v **XmlMapsXmlNameOutp return nil } +type awsRestxml_deserializeOpXmlMapWithXmlNamespace struct { +} + +func (*awsRestxml_deserializeOpXmlMapWithXmlNamespace) ID() string { + return "OperationDeserializer" +} + +func (m *awsRestxml_deserializeOpXmlMapWithXmlNamespace) HandleDeserialize(ctx context.Context, in middleware.DeserializeInput, next middleware.DeserializeHandler) ( + out middleware.DeserializeOutput, metadata middleware.Metadata, err error, +) { + out, metadata, err = next.HandleDeserialize(ctx, in) + if err != nil { + return out, metadata, err + } + + response, ok := out.RawResponse.(*smithyhttp.Response) + if !ok { + return out, metadata, &smithy.DeserializationError{Err: fmt.Errorf("unknown transport type %T", out.RawResponse)} + } + + if response.StatusCode < 200 || response.StatusCode >= 300 { + return out, metadata, awsRestxml_deserializeOpErrorXmlMapWithXmlNamespace(response, &metadata) + } + output := &XmlMapWithXmlNamespaceOutput{} + out.Result = output + + var buff [1024]byte + ringBuffer := smithyio.NewRingBuffer(buff[:]) + body := io.TeeReader(response.Body, ringBuffer) + rootDecoder := xml.NewDecoder(body) + t, err := smithyxml.FetchRootElement(rootDecoder) + if err == io.EOF { + return out, metadata, nil + } + if err != nil { + var snapshot bytes.Buffer + io.Copy(&snapshot, ringBuffer) + return out, metadata, &smithy.DeserializationError{ + Err: fmt.Errorf("failed to decode response body, %w", err), + Snapshot: snapshot.Bytes(), + } + } + + decoder := smithyxml.WrapNodeDecoder(rootDecoder, t) + err = awsRestxml_deserializeOpDocumentXmlMapWithXmlNamespaceOutput(&output, decoder) + if err != nil { + var snapshot bytes.Buffer + io.Copy(&snapshot, ringBuffer) + return out, metadata, &smithy.DeserializationError{ + Err: fmt.Errorf("failed to decode response body, %w", err), + Snapshot: snapshot.Bytes(), + } + } + + return out, metadata, err +} + +func awsRestxml_deserializeOpErrorXmlMapWithXmlNamespace(response *smithyhttp.Response, metadata *middleware.Metadata) error { + var errorBuffer bytes.Buffer + if _, err := io.Copy(&errorBuffer, response.Body); err != nil { + return &smithy.DeserializationError{Err: fmt.Errorf("failed to copy error response body, %w", err)} + } + errorBody := bytes.NewReader(errorBuffer.Bytes()) + + errorCode := "UnknownError" + errorMessage := errorCode + + errorComponents, err := awsxml.GetErrorResponseComponents(errorBody, false) + if err != nil { + return err + } + if reqID := errorComponents.RequestID; len(reqID) != 0 { + awsmiddleware.SetRequestIDMetadata(metadata, reqID) + } + if len(errorComponents.Code) != 0 { + errorCode = errorComponents.Code + } + if len(errorComponents.Message) != 0 { + errorMessage = errorComponents.Message + } + errorBody.Seek(0, io.SeekStart) + switch { + default: + genericError := &smithy.GenericAPIError{ + Code: errorCode, + Message: errorMessage, + } + return genericError + + } +} + +func awsRestxml_deserializeOpDocumentXmlMapWithXmlNamespaceOutput(v **XmlMapWithXmlNamespaceOutput, decoder smithyxml.NodeDecoder) error { + if v == nil { + return fmt.Errorf("unexpected nil of type %T", v) + } + var sv *XmlMapWithXmlNamespaceOutput + if *v == nil { + sv = &XmlMapWithXmlNamespaceOutput{} + } else { + sv = *v + } + + for { + t, done, err := decoder.Token() + if err != nil { + return err + } + if done { + break + } + originalDecoder := decoder + decoder = smithyxml.WrapNodeDecoder(originalDecoder.Decoder, t) + switch { + case strings.EqualFold("KVP", t.Name.Local): + nodeDecoder := smithyxml.WrapNodeDecoder(decoder.Decoder, t) + if err := awsRestxml_deserializeDocumentXmlMapWithXmlNamespaceInputOutputMap(&sv.MyMap, nodeDecoder); err != nil { + return err + } + + default: + // Do nothing and ignore the unexpected tag element + err = decoder.Decoder.Skip() + if err != nil { + return err + } + + } + decoder = originalDecoder + } + *v = sv + return nil +} + type awsRestxml_deserializeOpXmlNamespaces struct { } @@ -8269,6 +8537,55 @@ func awsRestxml_deserializeDocumentStructureListMember(v **types.StructureListMe return nil } +func awsRestxml_deserializeDocumentUnionPayload(v *types.UnionPayload, decoder smithyxml.NodeDecoder) error { + if v == nil { + return fmt.Errorf("unexpected nil of type %T", v) + } + var uv types.UnionPayload + var memberFound bool + for { + t, done, err := decoder.Token() + if err != nil { + return err + } + if done { + break + } + if memberFound { + if err = decoder.Decoder.Skip(); err != nil { + return err + } + } + originalDecoder := decoder + decoder = smithyxml.WrapNodeDecoder(originalDecoder.Decoder, t) + switch { + case strings.EqualFold("greeting", t.Name.Local): + var mv string + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + mv = xtv + } + uv = &types.UnionPayloadMemberGreeting{Value: mv} + memberFound = true + + default: + uv = &types.UnknownUnionMember{Tag: t.Name.Local} + memberFound = true + + } + decoder = originalDecoder + } + *v = uv + return nil +} + func awsRestxml_deserializeDocumentXmlAttributesInputOutput(v **types.XmlAttributesInputOutput, decoder smithyxml.NodeDecoder) error { if v == nil { return fmt.Errorf("unexpected nil of type %T", v) @@ -8521,6 +8838,104 @@ func awsRestxml_deserializeDocumentXmlMapsXmlNameInputOutputMapUnwrapped(v *map[ *v = sv return nil } +func awsRestxml_deserializeDocumentXmlMapWithXmlNamespaceInputOutputMap(v *map[string]string, decoder smithyxml.NodeDecoder) error { + if v == nil { + return fmt.Errorf("unexpected nil of type %T", v) + } + var sv map[string]string + if *v == nil { + sv = make(map[string]string, 0) + } else { + sv = *v + } + + for { + t, done, err := decoder.Token() + if err != nil { + return err + } + if done { + break + } + switch { + case strings.EqualFold("entry", t.Name.Local): + entryDecoder := smithyxml.WrapNodeDecoder(decoder.Decoder, t) + if err := awsRestxml_deserializeDocumentXmlMapWithXmlNamespaceInputOutputMapUnwrapped(&sv, entryDecoder); err != nil { + return err + } + + default: + err = decoder.Decoder.Skip() + if err != nil { + return err + } + + } + } + *v = sv + return nil +} + +func awsRestxml_deserializeDocumentXmlMapWithXmlNamespaceInputOutputMapUnwrapped(v *map[string]string, decoder smithyxml.NodeDecoder) error { + var sv map[string]string + if *v == nil { + sv = make(map[string]string, 0) + } else { + sv = *v + } + + var ek string + var ev string + for { + t, done, err := decoder.Token() + if err != nil { + return err + } + if done { + sv[ek] = ev + break + } + originalDecoder := decoder + decoder = smithyxml.WrapNodeDecoder(originalDecoder.Decoder, t) + switch { + case strings.EqualFold("K", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + ek = xtv + } + + case strings.EqualFold("V", t.Name.Local): + val, err := decoder.Value() + if err != nil { + return err + } + if val == nil { + break + } + { + xtv := string(val) + ev = xtv + } + + default: + err = decoder.Decoder.Skip() + if err != nil { + return err + } + + } + decoder = originalDecoder + } + *v = sv + return nil +} func awsRestxml_deserializeDocumentXmlNamespacedList(v *[]string, decoder smithyxml.NodeDecoder) error { if v == nil { return fmt.Errorf("unexpected nil of type %T", v) diff --git a/internal/protocoltest/restxml/generated.json b/internal/protocoltest/restxml/generated.json index 04cb6f7b9e8..981e34d59d1 100644 --- a/internal/protocoltest/restxml/generated.json +++ b/internal/protocoltest/restxml/generated.json @@ -45,6 +45,8 @@ "api_op_HttpPayloadWithMemberXmlName_test.go", "api_op_HttpPayloadWithStructure.go", "api_op_HttpPayloadWithStructure_test.go", + "api_op_HttpPayloadWithUnion.go", + "api_op_HttpPayloadWithUnion_test.go", "api_op_HttpPayloadWithXmlName.go", "api_op_HttpPayloadWithXmlName_test.go", "api_op_HttpPayloadWithXmlNamespace.go", @@ -112,6 +114,8 @@ "api_op_XmlIntEnums_test.go", "api_op_XmlLists.go", "api_op_XmlLists_test.go", + "api_op_XmlMapWithXmlNamespace.go", + "api_op_XmlMapWithXmlNamespace_test.go", "api_op_XmlMaps.go", "api_op_XmlMapsXmlName.go", "api_op_XmlMapsXmlName_test.go", diff --git a/internal/protocoltest/restxml/serializers.go b/internal/protocoltest/restxml/serializers.go index 1e4c1a4c58d..f4b973c2490 100644 --- a/internal/protocoltest/restxml/serializers.go +++ b/internal/protocoltest/restxml/serializers.go @@ -1327,6 +1327,81 @@ func awsRestxml_serializeOpHttpBindingsHttpPayloadWithStructureInput(v *HttpPayl return nil } +type awsRestxml_serializeOpHttpPayloadWithUnion struct { +} + +func (*awsRestxml_serializeOpHttpPayloadWithUnion) ID() string { + return "OperationSerializer" +} + +func (m *awsRestxml_serializeOpHttpPayloadWithUnion) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( + out middleware.SerializeOutput, metadata middleware.Metadata, err error, +) { + request, ok := in.Request.(*smithyhttp.Request) + if !ok { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown transport type %T", in.Request)} + } + + input, ok := in.Parameters.(*HttpPayloadWithUnionInput) + _ = input + if !ok { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown input parameters type %T", in.Parameters)} + } + + opPath, opQuery := httpbinding.SplitURI("/HttpPayloadWithUnion") + request.URL.Path = smithyhttp.JoinPath(request.URL.Path, opPath) + request.URL.RawQuery = smithyhttp.JoinRawQuery(request.URL.RawQuery, opQuery) + request.Method = "PUT" + var restEncoder *httpbinding.Encoder + if request.URL.RawPath == "" { + restEncoder, err = httpbinding.NewEncoder(request.URL.Path, request.URL.RawQuery, request.Header) + } else { + request.URL.RawPath = smithyhttp.JoinPath(request.URL.RawPath, opPath) + restEncoder, err = httpbinding.NewEncoderWithRawPath(request.URL.Path, request.URL.RawPath, request.URL.RawQuery, request.Header) + } + + if err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + + if input.Nested != nil { + if !restEncoder.HasHeader("Content-Type") { + ctx = smithyhttp.SetIsContentTypeDefaultValue(ctx, true) + restEncoder.SetHeader("Content-Type").String("application/xml") + } + + xmlEncoder := smithyxml.NewEncoder(bytes.NewBuffer(nil)) + payloadRootAttr := []smithyxml.Attr{} + payloadRoot := smithyxml.StartElement{ + Name: smithyxml.Name{ + Local: "nested", + }, + Attr: payloadRootAttr, + } + if err := awsRestxml_serializeDocumentUnionPayload(input.Nested, xmlEncoder.RootElement(payloadRoot)); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + payload := bytes.NewReader(xmlEncoder.Bytes()) + if request, err = request.SetStream(payload); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + } + + if request.Request, err = restEncoder.Encode(request.Request); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + in.Request = request + + return next.HandleSerialize(ctx, in) +} +func awsRestxml_serializeOpHttpBindingsHttpPayloadWithUnionInput(v *HttpPayloadWithUnionInput, encoder *httpbinding.Encoder) error { + if v == nil { + return fmt.Errorf("unsupported serialization of nil %T", v) + } + + return nil +} + type awsRestxml_serializeOpHttpPayloadWithXmlName struct { } @@ -4922,6 +4997,94 @@ func awsRestxml_serializeOpDocumentXmlMapsXmlNameInput(v *XmlMapsXmlNameInput, v return nil } +type awsRestxml_serializeOpXmlMapWithXmlNamespace struct { +} + +func (*awsRestxml_serializeOpXmlMapWithXmlNamespace) ID() string { + return "OperationSerializer" +} + +func (m *awsRestxml_serializeOpXmlMapWithXmlNamespace) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) ( + out middleware.SerializeOutput, metadata middleware.Metadata, err error, +) { + request, ok := in.Request.(*smithyhttp.Request) + if !ok { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown transport type %T", in.Request)} + } + + input, ok := in.Parameters.(*XmlMapWithXmlNamespaceInput) + _ = input + if !ok { + return out, metadata, &smithy.SerializationError{Err: fmt.Errorf("unknown input parameters type %T", in.Parameters)} + } + + opPath, opQuery := httpbinding.SplitURI("/XmlMapWithXmlNamespace") + request.URL.Path = smithyhttp.JoinPath(request.URL.Path, opPath) + request.URL.RawQuery = smithyhttp.JoinRawQuery(request.URL.RawQuery, opQuery) + request.Method = "POST" + var restEncoder *httpbinding.Encoder + if request.URL.RawPath == "" { + restEncoder, err = httpbinding.NewEncoder(request.URL.Path, request.URL.RawQuery, request.Header) + } else { + request.URL.RawPath = smithyhttp.JoinPath(request.URL.RawPath, opPath) + restEncoder, err = httpbinding.NewEncoderWithRawPath(request.URL.Path, request.URL.RawPath, request.URL.RawQuery, request.Header) + } + + if err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + + restEncoder.SetHeader("Content-Type").String("application/xml") + + xmlEncoder := smithyxml.NewEncoder(bytes.NewBuffer(nil)) + rootAttr := []smithyxml.Attr{} + root := smithyxml.StartElement{ + Name: smithyxml.Name{ + Local: "XmlMapWithXmlNamespaceInputOutput", + }, + Attr: rootAttr, + } + if err := awsRestxml_serializeOpDocumentXmlMapWithXmlNamespaceInput(input, xmlEncoder.RootElement(root)); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + if request, err = request.SetStream(bytes.NewReader(xmlEncoder.Bytes())); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + + if request.Request, err = restEncoder.Encode(request.Request); err != nil { + return out, metadata, &smithy.SerializationError{Err: err} + } + in.Request = request + + return next.HandleSerialize(ctx, in) +} +func awsRestxml_serializeOpHttpBindingsXmlMapWithXmlNamespaceInput(v *XmlMapWithXmlNamespaceInput, encoder *httpbinding.Encoder) error { + if v == nil { + return fmt.Errorf("unsupported serialization of nil %T", v) + } + + return nil +} + +func awsRestxml_serializeOpDocumentXmlMapWithXmlNamespaceInput(v *XmlMapWithXmlNamespaceInput, value smithyxml.Value) error { + defer value.Close() + if v.MyMap != nil { + rootAttr := []smithyxml.Attr{} + rootAttr = append(rootAttr, smithyxml.NewNamespaceAttribute("", "https://the-member.example.com")) + root := smithyxml.StartElement{ + Name: smithyxml.Name{ + Local: "KVP", + }, + Attr: rootAttr, + } + el := value.MemberElement(root) + if err := awsRestxml_serializeDocumentXmlMapWithXmlNamespaceInputOutputMap(v.MyMap, el); err != nil { + return err + } + } + return nil +} + type awsRestxml_serializeOpXmlNamespaces struct { } @@ -5546,6 +5709,27 @@ func awsRestxml_serializeDocumentStructureListMember(v *types.StructureListMembe return nil } +func awsRestxml_serializeDocumentUnionPayload(v types.UnionPayload, value smithyxml.Value) error { + defer value.Close() + switch uv := v.(type) { + case *types.UnionPayloadMemberGreeting: + customMemberNameAttr := []smithyxml.Attr{} + customMemberName := smithyxml.StartElement{ + Name: smithyxml.Name{ + Local: "greeting", + }, + Attr: customMemberNameAttr, + } + av := value.MemberElement(customMemberName) + av.String(uv.Value) + + default: + return fmt.Errorf("attempted to serialize unknown member type %T for union %T", uv, v) + + } + return nil +} + func awsRestxml_serializeDocumentXmlAttributesInputOutput(v *types.XmlAttributesInputOutput, value smithyxml.Value) error { defer value.Close() if v.Foo != nil { @@ -5624,6 +5808,36 @@ func awsRestxml_serializeDocumentXmlMapsXmlNameInputOutputMap(v map[string]types return nil } +func awsRestxml_serializeDocumentXmlMapWithXmlNamespaceInputOutputMap(v map[string]string, value smithyxml.Value) error { + if !value.IsFlattened() { + defer value.Close() + } + m := value.Map() + for key := range v { + entry := m.Entry() + keyElementAttr := []smithyxml.Attr{} + keyElementAttr = append(keyElementAttr, smithyxml.NewNamespaceAttribute("", "https://the-key.example.com")) + keyElement := smithyxml.StartElement{ + Name: smithyxml.Name{ + Local: "K", + }, + Attr: keyElementAttr, + } + entry.MemberElement(keyElement).String(key) + valueElementAttr := []smithyxml.Attr{} + valueElementAttr = append(valueElementAttr, smithyxml.NewNamespaceAttribute("", "https://the-value.example.com")) + valueElement := smithyxml.StartElement{ + Name: smithyxml.Name{ + Local: "V", + }, + Attr: valueElementAttr, + } + entry.MemberElement(valueElement).String(v[key]) + entry.Close() + } + return nil +} + func awsRestxml_serializeDocumentXmlNamespacedList(v []string, value smithyxml.Value) error { var array *smithyxml.Array if !value.IsFlattened() { diff --git a/internal/protocoltest/restxml/types/types.go b/internal/protocoltest/restxml/types/types.go index 041d802d22c..6f7a11e3c30 100644 --- a/internal/protocoltest/restxml/types/types.go +++ b/internal/protocoltest/restxml/types/types.go @@ -62,6 +62,21 @@ type StructureListMember struct { noSmithyDocumentSerde } +// The following types satisfy this interface: +// +// UnionPayloadMemberGreeting +type UnionPayload interface { + isUnionPayload() +} + +type UnionPayloadMemberGreeting struct { + Value string + + noSmithyDocumentSerde +} + +func (*UnionPayloadMemberGreeting) isUnionPayload() {} + type XmlAttributesInputOutput struct { Attr *string @@ -211,4 +226,5 @@ type UnknownUnionMember struct { noSmithyDocumentSerde } +func (*UnknownUnionMember) isUnionPayload() {} func (*UnknownUnionMember) isXmlUnionShape() {} diff --git a/internal/protocoltest/restxml/types/types_exported_test.go b/internal/protocoltest/restxml/types/types_exported_test.go index a697663cb06..3f2dba31577 100644 --- a/internal/protocoltest/restxml/types/types_exported_test.go +++ b/internal/protocoltest/restxml/types/types_exported_test.go @@ -7,6 +7,24 @@ import ( "github.com/aws/aws-sdk-go-v2/internal/protocoltest/restxml/types" ) +func ExampleUnionPayload_outputUsage() { + var union types.UnionPayload + // type switches can be used to check the union value + switch v := union.(type) { + case *types.UnionPayloadMemberGreeting: + _ = v.Value // Value is string + + case *types.UnknownUnionMember: + fmt.Println("unknown tag:", v.Tag) + + default: + fmt.Println("union is nil or unknown type") + + } +} + +var _ *string + func ExampleXmlUnionShape_outputUsage() { var union types.XmlUnionShape // type switches can be used to check the union value