9. Behavior traits#

9.1. Idempotency#

Operations marked with the readonly trait or idempotent trait are considered idempotent as defined in RFC 9110#section-9.2.2. Operations that contain a top-level input member marked with the idempotencyToken trait that are provided a token for the member are also considered idempotent. All other operations SHOULD be considered unsafe to retry unless the response to the operation is an error marked with the retryable trait or another kind of protocol-specific hint indicates the operation is safe to retry (for example, a Retry-After HTTP header, a 503 HTTP response, or a 429 HTTP response).

9.1.1. idempotencyToken trait#

Summary
Defines the input member of an operation that is used by the server to identify and discard replayed requests.
Trait selector

structure > :test(member > string)

Any structure member that targets a string

Value type
Annotation trait

Only a single member of the input of an operation can be targeted by the idempotencyToken trait; only top-level structure members of the input of an operation are considered.

A unique identifier (typically a UUID) SHOULD be used by the client when providing the value for the request token member. When the request token is present, the service MUST ensure that the request is not replayed within a service-defined period of time. This allows the client to safely retry operation invocations, including operations that are not read-only, that fail due to networking issues or internal server errors. The service uses the provided request token to identify and discard duplicate requests.

Client implementations MAY automatically provide a value for a request token member if and only if the member is not explicitly provided.

operation AllocateWidget {
    input: AllocateWidgetInput
}

@input
structure AllocateWidgetInput {
    @idempotencyToken
    clientToken: String
}

9.1.2. idempotent trait#

Summary
Indicates that the intended effect on the server of multiple identical requests with an operation is the same as the effect for a single such request.
Trait selector
operation
Value type
Annotation trait
Conflicts with
readonly trait
@idempotent
operation DeleteSomething {
    input: DeleteSomethingInput
    output: DeleteSomethingOutput
}

Note

All operations that are marked as readonly trait are inherently idempotent.

9.1.3. readonly trait#

Summary
Indicates that an operation is effectively read-only.
Trait selector
operation
Value type
Annotation trait
Conflicts with
idempotent trait
@readonly
operation GetSomething {
    input: GetSomethingInput
    output: GetSomethingOutput
}

9.1.4. retryable trait#

Summary
Indicates that an error MAY be retried by the client.
Trait selector

structure[trait|error]

A structure shape with the error trait

Value type
structure

The retryable trait is a structure that contains the following members:

Property Type Description
throttling boolean Indicates that the error is a retryable throttling error.
@error("server")
@retryable
@httpError(503)
structure ServiceUnavailableError {}

@error("client")
@retryable(throttling: true)
@httpError(429)
structure ThrottlingError {}

9.3. Compression#

Compression is the process of encoding, restructuring or otherwise modifying data in order to reduce its size and bandwidth capacity, with content encodings referenced in RFC 9110.

Smithy supports operations compressing requests from clients to services through the requestCompression trait.

9.3.1. requestCompression trait#

Summary
Indicates that an operation supports compressing requests from clients to services.
Trait selector
operation
Value type
structure
Validation
  1. Operation input members must not have both the streaming trait and requiresLength trait applied. This avoids the client reading and compressing the entire stream for the length of the compressed data to set the Content-Length header.
  2. encodings must not be empty, and all members must be valid, case-insensitive, supported compression algorithm values.

The requestCompression trait is a structure that contains the following members:

Property Type Description
encodings [string] Defines the priority-ordered list of compression algorithms supported by the service operation. Supported compression algorithms are: "gzip".

The following example defines an operation that supports gzip compression for requests from clients to services with both a streaming and non-streaming member.

$version: "2"
namespace smithy.example

@requestCompression(
    encodings: ["gzip"]
)
operation GetFoos {
    input := {
        streamingMember: StreamingFoo
        member: String
    }
}

@streaming
blob StreamingFoo

9.3.2. Request compression behavior#

Operations with the requestCompression trait applied direct clients to compress requests sent to services and set the corresponding encoding in the Content-Encoding header.

Operations with the requestCompression trait applied have request compression enabled by default, and clients SHOULD attempt to compress a request when a compression algorithm is supported (see DISABLE_REQUEST_COMPRESSION in Client Implementation to disable request compression).

Since compression is NOT required, services supporting operations with the requestCompression trait applied MUST be able to receive non-compressed requests, for cases such as clients not supporting certain compression algorithms or older versions of clients that have out-of-date supported compression algorithms.

The client MUST only compress the request using the first supported algorithm in encodings and stop considering algorithms that appear later in the list.

If a client does compress the request, they MUST also set the Content-Encoding header per RFC 9110#section-8.4:

If one or more encodings have been applied to a representation, the sender that applied the encodings MUST generate a Content-Encoding header field that lists the content codings in the order in which they were applied.

If a request has a structure member bound to the Content-Encoding header, the trait MAY still be applied. If the request is compressed, then the compression encoding MUST be appended to the Content-Encoding header after any user-provided encoding(s).

As an example, using the PutWithContentEncoding operation below with the customEncoding member set to brotli, the header would be "Content-Encoding": "brotli, gzip".

$version: "2"
namespace smithy.example

@requestCompression(
    encodings: ["gzip"]
)
operation PutWithContentEncoding {
    input: PutWithContentEncodingInput
}

@input
structure PutWithContentEncodingInput {
    @httpHeader("Content-Encoding")
    customEncoding: String // brotli

    @httpPayload
    data: String
}

Clients MUST encode the request content prior to request signing, otherwise the request signature will mismatch.

Because small payloads may become longer when compressed, operations SHOULD only be compressed when the payload size is greater than or equal to the value of the minimum compression threshold (see REQUEST_MIN_COMPRESSION_SIZE_BYTES in Client Implementation).

If the request contains a member with the streaming trait applied without the requiresLength trait applied, the request MUST be compressed if enabled regardless of the minimum compression threshold.

Operations with input members with both streaming trait and requiresLength trait are not allowed to use request compression. This avoids the client reading and compressing the entire stream for the length of the compressed data to set the Content-Length header.

9.3.3. Client Implementation#

Warning

The client configuration settings defined in this specification are still evolving and subject to change.

Smithy clients MUST expose a setting DISABLE_REQUEST_COMPRESSION to disable request compression. The value MUST be a boolean value which defaults to false. In order of precedence from highest to lowest, the setting shall be exposed:

  • Per-request configuration (SHOULD, if request-level configuration is supported by the client)
  • Service client configuration - DisableRequestCompression (MUST, with idiomatic casing/spacing for that client programming language)

Smithy clients MUST expose a setting REQUEST_MIN_COMPRESSION_SIZE_BYTES to specify the minimum size in bytes that a request body should be to trigger compression. The value MUST be a non-negative integer in the range 0 and 10485760 inclusive, and defaults to 10240 bytes. If the value is outside of the range, the client MUST throw an error. In order of precedence from highest to lowest, the setting shall be exposed:

  • Per-request configuration (SHOULD, if request-level configuration is supported by that client)
  • Service client configuration - RequestMinCompressionSizeBytes (MUST, with idiomatic casing/spacing for that client programming language)

If a client's language or standard library does not support a compression algorithm, they are not required to implement that algorithm. If none of the compression algorithms are supported by the client, then the request does not need to be compressed.

If the client's language or standard library exposes a "level" or "quality" setting to control the tradeoff between speed and the compressed size, clients MUST set this setting to an idiomatic default (either the default value for their language, or else a "balanced" mode).

9.3.4. Backward compatibility#

Once a compression algorithm is added to encodings, the algorithm SHOULD NOT be removed. If an algorithm is removed, the service MUST continue to support the removed algorithm on the server-side because older clients or non-official clients may continue sending compressed requests.