From 31ed5a383b47b83f66c7a67d92057bf42540cfe1 Mon Sep 17 00:00:00 2001 From: fossand Date: Wed, 7 Sep 2022 16:36:46 -0700 Subject: [PATCH] Add AwsQueryCompatible trait This commit introduces the `aws.protocols#awsQueryCompatible` trait which allows backward compatibility when migrating from awsQuery to awsJson1_0. --- .../source-1.0/spec/aws/aws-json.rst.template | 46 ++++++++++++++++ .../aws/protocols/aws-json.rst.template | 46 ++++++++++++++++ .../errors.smithy | 53 +++++++++++++++++++ .../awsJson1_0WithQueryCompatible/main.smithy | 18 +++++++ .../protocols/AwsQueryCompatibleTrait.java | 40 ++++++++++++++ ...re.amazon.smithy.model.traits.TraitService | 1 + .../META-INF/smithy/aws.protocols.smithy | 4 ++ .../errorfiles/aws-query-compatible.errors | 0 .../errorfiles/aws-query-compatible.smithy | 23 ++++++++ ...tible-does-not-support-non-aws-json.errors | 2 + ...tible-does-not-support-non-aws-json.smithy | 24 +++++++++ 11 files changed, 257 insertions(+) create mode 100644 smithy-aws-protocol-tests/model/awsJson1_0WithQueryCompatible/errors.smithy create mode 100644 smithy-aws-protocol-tests/model/awsJson1_0WithQueryCompatible/main.smithy create mode 100644 smithy-aws-traits/src/main/java/software/amazon/smithy/aws/traits/protocols/AwsQueryCompatibleTrait.java create mode 100644 smithy-aws-traits/src/test/resources/software/amazon/smithy/aws/traits/errorfiles/aws-query-compatible.errors create mode 100644 smithy-aws-traits/src/test/resources/software/amazon/smithy/aws/traits/errorfiles/aws-query-compatible.smithy create mode 100644 smithy-aws-traits/src/test/resources/software/amazon/smithy/aws/traits/errorfiles/protocols/aws-query-compatible-does-not-support-non-aws-json.errors create mode 100644 smithy-aws-traits/src/test/resources/software/amazon/smithy/aws/traits/errorfiles/protocols/aws-query-compatible-does-not-support-non-aws-json.smithy diff --git a/docs/source-1.0/spec/aws/aws-json.rst.template b/docs/source-1.0/spec/aws/aws-json.rst.template index 7d72f4abb17..c43f1cd17f7 100644 --- a/docs/source-1.0/spec/aws/aws-json.rst.template +++ b/docs/source-1.0/spec/aws/aws-json.rst.template @@ -192,6 +192,52 @@ In ``awsJson1_1``, servers SHOULD only send the error's for both protocols. See `Operation error serialization`_ for full details on how to deserialize errors for |quoted shape name|. +.. smithy-trait:: aws.protocols#awsQueryError +.. _aws.protocols#awsQueryError-trait: + +------------------------------------------ +``aws.protocols#awsQueryCompatible`` trait +------------------------------------------ + +Summary + When using the :ref:`awsQuery ` protocol, + custom ``Code`` and ``HTTP response code`` values can be defined for an error response via + the :ref:`awsQueryError ` trait. + + The ``awsQueryCompatible`` trait allows services to backward compatibly migrate from ``awsQuery`` to + :ref:`awsJson1_0 ` without removing values defined in the ``awsQueryError`` trait. + + This trait adds the ``x-amzn-query-error`` header in the form of ``Code;Fault`` to error responses. + ``Code`` is the value defined in the :ref:`awsQueryError `, + and ``Fault`` is one of ``Sender`` or ``Receiver``. + +Trait selector + ``service [trait|awsJson1_0]`` + +Value type + Annotation trait + +.. code-block:: smithy + + $version: "1" + use aws.protocols#awsQueryCompatible + use aws.protocols#awsQueryError + use aws.protocols#awsJson1_0 + + @awsQueryCompatible + @awsJson1_0 + service MyService { + version: "2020-02-05" + } + + @awsQueryError( + code: "InvalidThing", + httpResponseCode: 400, + ) + @error("client") + structure InvalidThingException { + message: String + } ------------------------- Protocol compliance tests diff --git a/docs/source-2.0/aws/protocols/aws-json.rst.template b/docs/source-2.0/aws/protocols/aws-json.rst.template index 8d83232c272..204842d982e 100644 --- a/docs/source-2.0/aws/protocols/aws-json.rst.template +++ b/docs/source-2.0/aws/protocols/aws-json.rst.template @@ -195,6 +195,52 @@ In ``awsJson1_1``, servers SHOULD only send the error's for both protocols. See `Operation error serialization`_ for full details on how to deserialize errors for |quoted shape name|. +.. smithy-trait:: aws.protocols#awsQueryError +.. _aws.protocols#awsQueryError-trait: + +------------------------------------------ +``aws.protocols#awsQueryCompatible`` trait +------------------------------------------ + +Summary + When using the :ref:`awsQuery ` protocol, + custom ``Code`` and ``HTTP response code`` values can be defined for an error response via + the :ref:`awsQueryError ` trait. + + The ``awsQueryCompatible`` trait allows services to backward compatibly migrate from ``awsQuery`` to + :ref:`awsJson1_0 ` without removing values defined in the ``awsQueryError`` trait. + + This trait adds the ``x-amzn-query-error`` header in the form of ``Code;Fault`` to error responses. + ``Code`` is the value defined in the :ref:`awsQueryError `, + and ``Fault`` is one of ``Sender`` or ``Receiver``. + +Trait selector + ``service [trait|awsJson1_0]`` + +Value type + Annotation trait + +.. code-block:: smithy + + $version: "2" + use aws.protocols#awsQueryCompatible + use aws.protocols#awsQueryError + use aws.protocols#awsJson1_0 + + @awsQueryCompatible + @awsJson1_0 + service MyService { + version: "2020-02-05" + } + + @awsQueryError( + code: "InvalidThing", + httpResponseCode: 400, + ) + @error("client") + structure InvalidThingException { + message: String + } ------------------------- Protocol compliance tests diff --git a/smithy-aws-protocol-tests/model/awsJson1_0WithQueryCompatible/errors.smithy b/smithy-aws-protocol-tests/model/awsJson1_0WithQueryCompatible/errors.smithy new file mode 100644 index 00000000000..ccc4b708718 --- /dev/null +++ b/smithy-aws-protocol-tests/model/awsJson1_0WithQueryCompatible/errors.smithy @@ -0,0 +1,53 @@ +$version: "2.0" + +namespace aws.protocoltests.json10 + +use aws.protocols#awsJson1_0 +use aws.protocols#awsQueryError +use smithy.test#httpRequestTests +use smithy.test#httpResponseTests + +@idempotent +operation GreetingWithError { + input: GreetingWithErrorInput, + output: GreetingWithErrorOutput, + errors: [InvalidGreetingError] +} + +@input +structure GreetingWithErrorInput { + greeting: String, +} + +@output +structure GreetingWithErrorOutput { + greeting: String, +} + +@awsQueryError( + code: "CustomGreetingErrorCode", + httpResponseCode: 402 +) +@error("client") +structure InvalidGreetingError { + Message: String, +} + +apply InvalidGreeting @httpResponseTests([ + { + id: "Json10WithQueryCompatibleGreetingError", + documentation: "@awsQueryCompatible trait is applied to service", + protocol: awsJson1_0, + params: { + Message: "Hi" + }, + code: 402, + headers: { + "Content-Type": "application/x-amz-json-1.0", + "x-amzn-query-error": "CustomGreetingErrorCode;Sender" + }, + bodyMediaType: "application/json", + body: "{\"__type\": \"InvalidGreetingError\",\"Message\": \"Hi\"}", + appliesTo: "client" + }, +]) diff --git a/smithy-aws-protocol-tests/model/awsJson1_0WithQueryCompatible/main.smithy b/smithy-aws-protocol-tests/model/awsJson1_0WithQueryCompatible/main.smithy new file mode 100644 index 00000000000..5ca7d211c30 --- /dev/null +++ b/smithy-aws-protocol-tests/model/awsJson1_0WithQueryCompatible/main.smithy @@ -0,0 +1,18 @@ +$version: "2.0" + +namespace aws.protocoltests.json10 + +use aws.api#service +use aws.protocols#awsJson1_0 +use aws.protocols#awsQueryCompatible +use smithy.test#httpRequestTests +use smithy.test#httpResponseTests + + +@service(sdkId: "JSON RPC 10 with Query Compatible Trait") +@awsQueryCompatible +@awsJson1_0 +service JsonRpc10WithQueryCompatible { + version: "2020-07-14", + operations: [GreetingWithErrors] +} diff --git a/smithy-aws-traits/src/main/java/software/amazon/smithy/aws/traits/protocols/AwsQueryCompatibleTrait.java b/smithy-aws-traits/src/main/java/software/amazon/smithy/aws/traits/protocols/AwsQueryCompatibleTrait.java new file mode 100644 index 00000000000..29d5e4c3b02 --- /dev/null +++ b/smithy-aws-traits/src/main/java/software/amazon/smithy/aws/traits/protocols/AwsQueryCompatibleTrait.java @@ -0,0 +1,40 @@ +/* + * Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.smithy.aws.traits.protocols; + +import software.amazon.smithy.model.node.Node; +import software.amazon.smithy.model.node.ObjectNode; +import software.amazon.smithy.model.shapes.ShapeId; +import software.amazon.smithy.model.traits.AnnotationTrait; + +public final class AwsQueryCompatibleTrait extends AnnotationTrait { + + public static final ShapeId ID = ShapeId.from("aws.protocols#awsQueryCompatible"); + + public AwsQueryCompatibleTrait(ObjectNode node) { + super(ID, node); + } + + public AwsQueryCompatibleTrait() { + this(Node.objectNode()); + } + + public static final class Provider extends AnnotationTrait.Provider { + public Provider() { + super(ID, AwsQueryCompatibleTrait::new); + } + } +} diff --git a/smithy-aws-traits/src/main/resources/META-INF/services/software.amazon.smithy.model.traits.TraitService b/smithy-aws-traits/src/main/resources/META-INF/services/software.amazon.smithy.model.traits.TraitService index 9ba4ae0de99..77e89519faa 100644 --- a/smithy-aws-traits/src/main/resources/META-INF/services/software.amazon.smithy.model.traits.TraitService +++ b/smithy-aws-traits/src/main/resources/META-INF/services/software.amazon.smithy.model.traits.TraitService @@ -12,6 +12,7 @@ software.amazon.smithy.aws.traits.clientendpointdiscovery.ClientDiscoveredEndpoi software.amazon.smithy.aws.traits.customizations.S3UnwrappedXmlOutputTrait$Provider software.amazon.smithy.aws.traits.HttpChecksumTrait$Provider software.amazon.smithy.aws.traits.protocols.AwsQueryErrorTrait$Provider +software.amazon.smithy.aws.traits.protocols.AwsQueryCompatibleTrait$Provider software.amazon.smithy.aws.traits.protocols.AwsQueryTrait$Provider software.amazon.smithy.aws.traits.protocols.Ec2QueryNameTrait$Provider software.amazon.smithy.aws.traits.protocols.Ec2QueryTrait$Provider diff --git a/smithy-aws-traits/src/main/resources/META-INF/smithy/aws.protocols.smithy b/smithy-aws-traits/src/main/resources/META-INF/smithy/aws.protocols.smithy index 23fcbc997a8..5099667c77c 100644 --- a/smithy-aws-traits/src/main/resources/META-INF/smithy/aws.protocols.smithy +++ b/smithy-aws-traits/src/main/resources/META-INF/smithy/aws.protocols.smithy @@ -81,6 +81,10 @@ structure awsQueryError { httpResponseCode: Integer } +/// Enable backward compatibility when migrating from awsQuery to awsJson protocol +@trait(selector: "service [trait|aws.protocols#awsJson1_0]") +structure awsQueryCompatible {} + /// An RPC-based protocol that sends 'POST' requests in the body as Amazon EC2 /// formatted `x-www-form-urlencoded` strings and responses in XML documents. /// This protocol does not use HTTP binding traits. diff --git a/smithy-aws-traits/src/test/resources/software/amazon/smithy/aws/traits/errorfiles/aws-query-compatible.errors b/smithy-aws-traits/src/test/resources/software/amazon/smithy/aws/traits/errorfiles/aws-query-compatible.errors new file mode 100644 index 00000000000..e69de29bb2d diff --git a/smithy-aws-traits/src/test/resources/software/amazon/smithy/aws/traits/errorfiles/aws-query-compatible.smithy b/smithy-aws-traits/src/test/resources/software/amazon/smithy/aws/traits/errorfiles/aws-query-compatible.smithy new file mode 100644 index 00000000000..a748c687ef5 --- /dev/null +++ b/smithy-aws-traits/src/test/resources/software/amazon/smithy/aws/traits/errorfiles/aws-query-compatible.smithy @@ -0,0 +1,23 @@ +$version: "2.0" + +namespace smithy.example + +use aws.protocols#awsQueryCompatible +use aws.protocols#awsQueryError +use aws.protocols#awsJson1_0 + +@awsQueryCompatible +@awsJson1_0 +service MyService { + version: "2020-02-05", + errors: [InvalidThingException] +} + +@awsQueryError( + code: "InvalidThing", + httpResponseCode: 400, +) +@error("client") +structure InvalidThingException { + message: String +} diff --git a/smithy-aws-traits/src/test/resources/software/amazon/smithy/aws/traits/errorfiles/protocols/aws-query-compatible-does-not-support-non-aws-json.errors b/smithy-aws-traits/src/test/resources/software/amazon/smithy/aws/traits/errorfiles/protocols/aws-query-compatible-does-not-support-non-aws-json.errors new file mode 100644 index 00000000000..af5c295f0ff --- /dev/null +++ b/smithy-aws-traits/src/test/resources/software/amazon/smithy/aws/traits/errorfiles/protocols/aws-query-compatible-does-not-support-non-aws-json.errors @@ -0,0 +1,2 @@ +[WARNING] smithy.example#MyService: This shape applies a trait that is deprecated: aws.protocols#awsQuery | DeprecatedTrait +[ERROR] smithy.example#MyService: Trait `aws.protocols#awsQueryCompatible` cannot be applied to `smithy.example#MyService`. This trait may only be applied to shapes that match the following selector: service [trait|aws.protocols#awsJson1_0] | TraitTarget diff --git a/smithy-aws-traits/src/test/resources/software/amazon/smithy/aws/traits/errorfiles/protocols/aws-query-compatible-does-not-support-non-aws-json.smithy b/smithy-aws-traits/src/test/resources/software/amazon/smithy/aws/traits/errorfiles/protocols/aws-query-compatible-does-not-support-non-aws-json.smithy new file mode 100644 index 00000000000..110bff6c730 --- /dev/null +++ b/smithy-aws-traits/src/test/resources/software/amazon/smithy/aws/traits/errorfiles/protocols/aws-query-compatible-does-not-support-non-aws-json.smithy @@ -0,0 +1,24 @@ +$version: "2.0" + +namespace smithy.example + +use aws.protocols#awsQueryCompatible +use aws.protocols#awsQueryError +use aws.protocols#awsQuery + +@awsQueryCompatible +@awsQuery +@xmlNamespace(uri: "https://example.com") +service MyService { + version: "2020-02-05", + errors: [InvalidThingException] +} + +@awsQueryError( + code: "InvalidThing", + httpResponseCode: 400, +) +@error("client") +structure InvalidThingException { + message: String +}