

# Configuring service clients in the Amazon SDK for Rust
Configuring service clients

 To programmatically access Amazon Web Services services, the Amazon SDK for Rust uses a client struct for each Amazon Web Services service. For example, if your application needs to access Amazon EC2, your application creates an Amazon EC2 client struct to interface with that service. You then use the service client to make requests to that Amazon Web Services service. 

To make a request to an Amazon Web Services service, you must first create a service client. For each Amazon Web Services service your code uses, it has its own crate and its own dedicated type for interacting with it. The client exposes one method for each API operation exposed by the service. 

There are many alternative ways to configure SDK behavior, but ultimately everything has to do with the behavior of service clients. Any configuration has no effect until a service client that is created from them is used.

You must establish how your code authenticates with Amazon when you develop with Amazon Web Services services. You must also set the Amazon Web Services Region you want to use.

The [Amazon SDKs and Tools Reference Guide](https://docs.amazonaws.cn/sdkref/latest/guide/) also contains settings, features, and other foundational concepts common among many of the Amazon SDKs. 

**Topics**
+ [Client configuration externally](config-external.md)
+ [Client configuration in code](config-code.md)
+ [Amazon Web Services Region](region.md)
+ [Credential providers](credproviders.md)
+ [Behavior versions](behavior-versions.md)
+ [Retries](retries.md)
+ [Timeouts](timeouts.md)
+ [Observability](observability.md)
+ [Client endpoints](endpoints.md)
+ [Overriding an operation configuration](peroperation.md)
+ [HTTP](http.md)
+ [Interceptors](interceptors.md)

# Configuring Amazon SDK for Rust service clients externally
Client configuration externally

Many configuration settings can be handled outside of your code. When configuration is handled externally, the configuration is applied across all of your applications. Most configuration settings can be set as either environment variables or in a separate shared Amazon `config` file. The shared `config` file can maintain separate sets of settings, called profiles, to provide different configurations for different environments or tests.

Environment variables and shared `config` file settings are standardized and shared across Amazon SDKs and tools to support consistent functionality across different programming languages and applications.

See the *Amazon SDKs and Tools Reference Guide* to learn about configuring your application through these methods, plus details on each cross-sdk setting. To see all the all settings that the SDK can resolve from the environment variables or configuration files, see the [Settings reference](https://docs.amazonaws.cn/sdkref/latest/guide/settings-reference.html) in the *Amazon SDKs and Tools Reference Guide*.

To make a request to an Amazon Web Services service, you first instantiate a client for that service. You can configure common settings for service clients such as timeouts, the HTTP client, and retry configuration. 

Each service client requires an Amazon Web Services Region and a credential provider. The SDK uses these values to send requests to the correct Region for your resources and to sign requests with the correct credentials. You can specify these values programmatically in code or have them automatically loaded from the environment.

The SDK has a series of places (or sources) that it checks in order to find a value for configuration settings.

1. Any explicit setting set in the code or on a service client itself takes precedence over anything else.

1. Environment variables
   + For details on setting environment variables, see [environment variables](https://docs.amazonaws.cn/sdkref/latest/guide/environment-variables.html) in the *Amazon SDKs and Tools Reference Guide*.
   + Note that you can configure environment variables for a shell at different levels of scope: system-wide, user-wide, and for a specific terminal session.

1. Shared `config` and `credentials` files
   + For details on setting up these files, see the [Shared `config` and `credentials` files](https://docs.amazonaws.cn/sdkref/latest/guide/file-format.html) in the *Amazon SDKs and Tools Reference Guide*.

1. Any default value provided by the SDK source code itself is used last.
   + Some properties, such as Region, don't have a default. You must specify them either explicitly in code, in an environment setting, or in the shared `config` file. If the SDK can't resolve required configuration, API requests can fail at runtime.

# Configuring Amazon SDK for Rust service clients in code
Client configuration in code

When configuration is handled directly in code, the configuration scope is limited to the application that uses that code. Within that application, there are options for the global configuration of all service clients, the configuration to all clients of a certain Amazon Web Services service type, or the configuration to a specific service client instance.

To make a request to an Amazon Web Services service, you first instantiate a client for that service. You can configure common settings for service clients such as timeouts, the HTTP client, and retry configuration. 

Each service client requires an Amazon Web Services Region and a credential provider. The SDK uses these values to send requests to the correct Region for your resources and to sign requests with the correct credentials. You can specify these values programmatically in code or have them automatically loaded from the environment.

**Note**  
Service clients can be expensive to construct and are generally meant to be shared. To facilitate this, all `Client` structs implement `Clone`.

## Configure a client from the environment


To create a client with environment-sourced configuration, use static methods from the `aws-config` crate:

```
let config = aws_config::defaults(BehaviorVersion::latest())
    .load()
    .await;

let s3 = aws_sdk_s3::Client::new(&config);
```

Creating a client this way is useful when running on Amazon Elastic Compute Cloud, Amazon Lambda, or any other context where the configuration of a service client is available directly from the environment. This decouples your code from the environment that it's running in and makes it easier to deploy your application to multiple Amazon Web Services Regions without changing the code.

You can explicitly override specific properties. Explicit configuration takes precedence over configuration resolved from the execution environment. The following example loads configuration from the environment, but explicitly overrides the Amazon Web Services Region:

```
let config = aws_config::defaults(BehaviorVersion::latest())
    .region("us-east-1")
    .load()
    .await;
    
let s3 = aws_sdk_s3::Client::new(&config);
```

**Note**  
Not all configuration values are sourced by the client at creation time. Credential-related settings, such as temporary access keys and IAM Identity Center configuration, are accessed by the credential provider layer when the client is used to make a request.

The code `BehaviorVersion::latest()` shown in the prior examples indicates the version of the SDK to use for defaults. `BehaviorVersion::latest()` is appropriate for most cases. For details, see [Using behavior versions in the Amazon SDK for Rust](behavior-versions.md).

## Use the builder pattern for service-specific settings


There are some options that can only be configured on a specific service client type. However, most often, you'll still want to load the majority of configuration from the environment, and then specifically add the additional options. The builder pattern is a common pattern within the Amazon SDK for Rust crates. You first load the general configuration using `aws_config::defaults`, then use the `from` method to load that configuration into the builder for the service you are working with. You can then set any unique configuration values for that service and call `build`. Lastly, the client is created from this modfied configuration. 

```
// Call a static method on aws-config that sources default config values.
let config = aws_config::defaults(BehaviorVersion::latest())
    .load()
    .await;

// Use the Builder for S3 to create service-specific config from the default config.
let s3_config = aws_sdk_s3::config::Builder::from(&config)
    .accelerate(true) // Set an S3-only configuration option
    .build();

// Create the client.
let s3 = aws_sdk_s3::Client::from_conf(s3_config);
```

One way to discover additional methods that are available for a specific type of service client is to use the API documentation, such as for [https://docs.rs/aws-sdk-s3/latest/aws_sdk_s3/config/struct.Builder.html](https://docs.rs/aws-sdk-s3/latest/aws_sdk_s3/config/struct.Builder.html).

## Advanced explicit client configuration


To configure a service client with specific values instead of loading a configuration from the environment, you can specify them on the client `Config` builder as shown in the following:

```
let conf = aws_sdk_s3::Config::builder()
    .region("us-east-1")
    .endpoint_resolver(my_endpoint_resolver)
    .build();

let s3 = aws_sdk_s3::Client::from_conf(conf);
```

When you create a service configuration with `aws_sdk_s3::Config::builder()`, *no default configuration is loaded*. Defaults are only loaded when creating a config based on `aws_config::defaults`. 

There are some options that can only be configured on a specific service client type. The previous example shows an example of this by using the `endpoint_resolver` function on a Amazon S3 client.

# Setting the Amazon Web Services Region for the the Amazon SDK for Rust
Amazon Web Services Region

You can access Amazon Web Services services that operate in a specific geographic area by using Amazon Web Services Regions. This can be useful both for redundancy and to keep your data and applications running close to where you and your users access them. For more information on how Regions are used, see [Amazon Web Services Region](https://docs.amazonaws.cn/sdkref/latest/guide/feature-region.html) in the *Amazon SDKs and Tools Reference Guide*.

**Important**  
Most resources reside in a specific Amazon Web Services Region and you must supply the correct Region for the resource when using the SDK.

You must set a default Amazon Web Services Region for the SDK for Rust to use for Amazon requests. This default is used for any SDK service method calls that aren't specified with a Region. 

For examples on how to set the default region through the shared Amazon `config` file or environment variables, see [Amazon Web Services Region](https://docs.amazonaws.cn/sdkref/latest/guide/feature-region.html) in the *Amazon SDKs and Tools Reference Guide*.

## Amazon Web Services Region provider chain


 The following lookup process is used when loading a service client's configuration from the execution environment. The first value that the SDK finds set is used in the configuration of the client. For more information on creating service clients, see [Configure a client from the environment](config-code.md#configure-a-client-from-the-environment).

1. Any explicit Region set programmatically.

1. The `AWS_REGION` environment variable is checked. 
   + If you are using the Amazon Lambda service, this environment variable is set automatically by the Amazon Lambda container.

1. The `region` property in the shared Amazon `config` file is checked. 
   + The `AWS_CONFIG_FILE` environment variable can be used to change the location of the shared `config` file. To learn more about where this file is kept, see [Location of the shared `config` and `credentials` files](https://docs.amazonaws.cn/sdkref/latest/guide/file-location.html) in the *Amazon SDKs and Tools Reference Guide*.
   + The `AWS_PROFILE` environment variable can be used to select a named profile instead of the default. To learn more about configuring different profiles, see [Shared `config` and `credentials` files](https://docs.amazonaws.cn/sdkref/latest/guide/file-format.html) in the *Amazon SDKs and Tools Reference Guide*.

1. The SDK attempts to use the Amazon EC2 Instance Metadata Service to determine the Region of the currently running Amazon EC2 instance.
   + The Amazon SDK for Rust only supports IMDSv2.

The `RegionProviderChain` is automatically used with no additional code when creating a basic configuration to use with a service client:

```
let config = aws_config::defaults(BehaviorVersion::latest())
    .load()
    .await;
```

## Setting the Amazon Web Services Region in code


### Explicitly setting the Region in code


Use `Region::new()` directly in your configuration when you want to explicitly set the Region. 

The Region provider chain is not used - it does not check the environment, shared `config` file, or Amazon EC2 Instance Metadata Service. 

```
use aws_config::{defaults, BehaviorVersion};
use aws_sdk_s3::config::Region;

#[tokio::main]
async fn main() {
    let config = defaults(BehaviorVersion::latest())
        .region(Region::new("us-west-2"))
        .load()
        .await;

    println!("Using Region: {}", config.region().unwrap());
}
```

Be sure you are entering a valid string for an Amazon Web Services Region; the value provided is not validated.

### Customizing the `RegionProviderChain`


Use the [Amazon Web Services Region provider chain](#region-provider-chain) when you want to inject a Region conditionally, override it, or customize the resolution chain.

```
use aws_config::{defaults, BehaviorVersion};
use aws_config::meta::region::RegionProviderChain;
use aws_sdk_s3::config::Region;
use std::env;

#[tokio::main]
async fn main() {  
    let region_provider = RegionProviderChain::first_try(env::var("CUSTOM_REGION").ok().map(Region::new))
        .or_default_provider()
        .or_else(Region::new("us-east-2"));
    
    let config = aws_config::defaults(BehaviorVersion::latest())
        .region(region_provider)
        .load()
        .await;

    println!("Using Region: {}", config.region().unwrap());
}
```

 The previous configuration will:

1. First see if there is a string set in the `CUSTOM_REGION` environment variable.

1. If that's not available, fall back to the default Region provider chain.

1. If that fails, use "us-east-2" as the final fallback.

# Using Amazon SDK for Rust credential providers
Credential providers

 All requests to Amazon must be cryptographically signed by using credentials issued by Amazon. At runtime, the SDK retrieves configuration values for credentials by checking several locations.

If the retrieved configuration includes [Amazon IAM Identity Center single sign-on access settings](credentials.md), the SDK works with the IAM Identity Center to retrieve temporary credentials that it uses to make request to Amazon Web Services services.

If the retrieved configuration includes [temporary credentials](https://docs.amazonaws.cn/sdkref/latest/guide/access-temp-idc.html), the SDK uses them to make Amazon Web Services service calls. Temporary credentials consist of access keys and a session token.

Authentication with Amazon can be handled outside of your codebase. Many authentication methods can be automatically detected, used, and refreshed by the SDK using the credential provider chain.

For guided options for getting started on Amazon authentication for your project, see [Authentication and access](https://docs.amazonaws.cn/sdkref/latest/guide/access.html) in the *Amazon SDKs and Tools Reference Guide*.

## The credential provider chain


If you don't explicitly specify a credential provider when constructing a client, the SDK for Rust uses a credential provider chain that checks a series of places where you can supply credentials. Once the SDK finds credentials in one of these locations, the search stops. For details on constructing clients, see [Configuring Amazon SDK for Rust service clients in code](config-code.md).

The following example doesn't specify a credential provider in the code. The SDK uses the credential provider chain to detect the authentication that has been set up in the hosting environment, and uses that authentication for calls to Amazon Web Services services.

```
let config = aws_config::defaults(BehaviorVersion::latest()).load().await;
let s3 = aws_sdk_s3::Client::new(&config);
```

### Credential retrieval order


The credential provider chain searches for credentials using the following predefined sequence:

1. **Access key environment variables**

   The SDK attempts to load credentials from the `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`, and `AWS_SESSION_TOKEN` environment variables.

1. **The shared Amazon `config` and `credentials` files**

   The SDK attempts to load credentials from the `[default]` profile in the shared Amazon `config` and `credentials` files. You can use the `AWS_PROFILE` environment variable to choose a named profile you want the SDK to load instead of using `[default]`. The `config` and `credentials` files are shared by various Amazon SDKs and tools. For more information on these files, see the [Shared `config` and `credentials` files](https://docs.amazonaws.cn/sdkref/latest/guide/file-format.html) in the *Amazon SDKs and Tools Reference Guide*. For more information on standardized providers you can specify in a profile, see [Amazon SDKs and Tools standardized credential providers](https://docs.aws.amazon.com/sdkref/latest/guide/standardized-credentials.html).

1. **Amazon STS web identity**

   When creating mobile applications or client-based web applications that require access to Amazon, Amazon Security Token Service (Amazon STS) returns a set of temporary security credentials for federated users who are authenticated through a public identity provider (IdP).
   + When you specify this in a profile, the SDK or tool attempts to retrieve temporary credentials using Amazon STS `AssumeRoleWithWebIdentity` API method. For details on this method, see [AssumeRoleWithWebIdentity](https://docs.amazonaws.cn/STS/latest/APIReference/API_AssumeRoleWithWebIdentity.html) in the *Amazon Security Token Service API Reference*.
   +  For guidance on configuring this provider, see [Federate with web identity or OpenID Connect](https://docs.amazonaws.cn/sdkref/latest/guide/access-assume-role.html#webidentity) in the *Amazon SDKs and Tools Reference Guide*.
   +  For details on SDK configuration properties for this provider, see [Assume role credential provider](https://docs.amazonaws.cn/sdkref/latest/guide/feature-assume-role-credentials.html) in the *Amazon SDKs and Tools Reference Guide*.

1. **Amazon ECS and Amazon EKS container credentials **

   Your Amazon Elastic Container Service tasks and Kubernetes service accounts can have an IAM role associated with them. The permissions granted in the IAM role are assumed by the containers running in the task or containers of the pod. This role allows your SDK for Rust application code (on the container) to use other Amazon Web Services services.

   The SDK attempts to retrieve credentials from the `AWS_CONTAINER_CREDENTIALS_RELATIVE_URI` or `AWS_CONTAINER_CREDENTIALS_FULL_URI` environment variables, which can be set automatically by Amazon ECS and Amazon EKS.
   + For details on setting up this role for Amazon ECS, see [ Amazon ECS task IAM role](https://docs.amazonaws.cn/AmazonECS/latest/developerguide/task-iam-roles.html) in the *Amazon Elastic Container Service Developer Guide*.
   + For Amazon EKS setup information, see [Setting up the Amazon EKS Pod Identity Agent](https://docs.amazonaws.cn/eks/latest/userguide/pod-id-agent-setup.html) in the **Amazon EKS User Guide**.
   +  For details on SDK configuration properties for this provider, see [Container credential provider](https://docs.amazonaws.cn/sdkref/latest/guide/feature-container-credentials.html) in the *Amazon SDKs and Tools Reference Guide*.

1. **Amazon EC2 Instance Metadata Service **

   Create an IAM role and attach it to your instance. The SDK for Rust application on the instance attempts to retrieve the credentials provided by the role from the instance metadata. 
   + The SDK for Rust only supports [IMDSv2](https://docs.amazonaws.cn/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html).
   + For details on setting up this role and using metadata, [IAM roles for Amazon EC2](https://docs.amazonaws.cn/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html) and [Work with instance metadata](https://docs.amazonaws.cn/AWSEC2/latest/UserGuide/ec2-instance-metadata.html) in the *Amazon EC2 User Guide*.
   +  For details on SDK configuration properties for this provider, see [IMDS credential provider](https://docs.amazonaws.cn/sdkref/latest/guide/feature-imds-credentials.html) in the *Amazon SDKs and Tools Reference Guide*.

1. If credentials still aren't resolved at this point, the operation panics with an error.

For details on Amazon credential provider configuration settings, see [Standardized credential providers](https://docs.amazonaws.cn/sdkref/latest/guide/standardized-credentials.html) in the *Settings reference* of the *Amazon SDKs and Tools Reference Guide*.

## Explicit credential provider


Instead of relying on the credential provider chain to detect your authentication method, you can specify a specific credential provider that the SDK should use. When you load your general configuration using `aws_config::defaults`, you can specify a custom credential provider as shown in the following:

```
let config = aws_config::defaults(BehaviorVersion::latest())
    .credentials_provider(MyCredentialsProvider::new())
    .load()
    .await;
```

You can implement your own credential provider by implementing the [https://docs.rs/aws-credential-types/latest/aws_credential_types/provider/trait.ProvideCredentials.html](https://docs.rs/aws-credential-types/latest/aws_credential_types/provider/trait.ProvideCredentials.html) trait.

## Identity caching


The SDK will cache credentials and other identity types such as SSO tokens. By default, the SDK uses a lazy cache implementation that loads credentials upon first request, caches them, and then attempts to refresh them during another request when they are close to expiring. Clients created from the same `SdkConfig` will share an [https://docs.rs/aws-smithy-runtime/latest/aws_smithy_runtime/client/identity/struct.IdentityCache.html](https://docs.rs/aws-smithy-runtime/latest/aws_smithy_runtime/client/identity/struct.IdentityCache.html).

# Using behavior versions in the Amazon SDK for Rust
Behavior versions

Amazon SDK for Rust developers expect and rely upon the robust and predictable behavior the language and its major libraries offer. To help developers using the SDK for Rust get the expected behavior, client configurations are required to include a `BehaviorVersion`. The `BehaviorVersion` specifies the version of the SDK whose defaults are expected. This lets the SDK evolve over time, changing best practices to match new standards and support new features without unexpected adverse impact on your application's behavior.

**Warning**  
If you try to configure the SDK or create a client without explicitly specifying a `BehaviorVersion`, the constructor will panic.

For example, imagine that a new version of the SDK is released with a new default retry policy. If your application uses a `BehaviorVersion` matching a previous version of the SDK, then that prior configuration is used instead of the new default configuration.

Each time a new behavior version of the SDK for Rust is released, the previous `BehaviorVersion` is marked with the SDK for Rust `deprecated` attribute and the new version is added. This causes warnings to occur at compile time, but otherwise lets the build continue as usual. `BehaviorVersion::latest()` is also updated to indicate the new version's default behavior.

**Note**  
If your code isn't reliant on extremely specific behavior characteristics, you should use `BehaviorVersion::latest()` in code or use the feature flag `behavior-version-latest` in the `Cargo.toml` file. If you're writing code that's latency sensitive, or that tunes Rust SDK behaviors, consider pinning `BehaviorVersion` to a specific major version.

## Set the behavior version in `Cargo.toml`


You can specify the behavior version for the SDK and individual modules,such as `aws-sdk-s3` or `aws-sdk-iam`, by including an appropriate feature flag in the `Cargo.toml` file. At this time, only the `latest` version of the SDK is supported in `Cargo.toml`:

```
[dependencies]
aws-config = { version = "1", features = ["behavior-version-latest"] }
aws-sdk-s3 = { version = "1", features = ["behavior-version-latest"] }
```

## Set the behavior version in code


Your code can change the behavior version as needed by specifying it when configuring the SDK or a client:

```
let config = aws_config::load_defaults(BehaviorVersion::v2023_11_09()).await;
```

This example creates a configuration that uses the environment to configure the SDK but sets the `BehaviorVersion` to `v2023_11_09()`.

# Configuring retries in the Amazon SDK for Rust
Retries

The Amazon SDK for Rust provides a default retry behavior for service requests and customizable configuration options. Calls to Amazon Web Services services occasionally return unexpected exceptions. Certain types of errors, such as throttling or transient errors, might be successful if the call is retried. 

Retry behavior can be configured globally using environment variables or settings in the shared Amazon `config` file. For information on this approach, see [Retry behavior](https://docs.amazonaws.cn/sdkref/latest/guide/feature-retry-behavior.html) in the *Amazon SDKs and Tools Reference Guide*. It also includes detailed information on retry strategy implementations and how to choose one over another. 

Alternatively, these options can also be configured in your code, as shown in the following sections.

## Default retry configuration


 Every service client defaults to the `standard` retry strategy configuration provided through the [https://docs.rs/aws-smithy-types/latest/aws_smithy_types/retry/struct.RetryConfig.html](https://docs.rs/aws-smithy-types/latest/aws_smithy_types/retry/struct.RetryConfig.html) struct. By default, a call will be tried three times (*the initial attempt, plus two retries*). Additionally, each retry will be delayed by a short, random duration to avoid retry storms. This convention is suitable for the majority of use cases but might be unsuitable in specific circumstances such as high-throughput systems. 

 Only some types of errors are considered retryable by the SDKs. Examples of retryable errors are: 
+ socket timeouts
+ service-side throttling
+ transient service errors like HTTP 5XX responses

The following examples are **not** considered retryable:
+ Missing or invalid parameters
+ authentication/security errors
+ misconfiguration exceptions

You can customize the `standard` retry strategy by setting the maximum attempts, delays, and backoff configuration. 

## Maximum Attempts


You can customize the maximum attempts in your code by supplying a modified [https://docs.rs/aws-smithy-types/latest/aws_smithy_types/retry/struct.RetryConfig.html](https://docs.rs/aws-smithy-types/latest/aws_smithy_types/retry/struct.RetryConfig.html) to your `aws_config::defaults`: 

```
const CUSTOM_MAX_ATTEMPTS: u32 = 5;
let retry_config = RetryConfig::standard()
    // Set max attempts. When max_attempts is 1, there are no retries.
    // This value MUST be greater than zero.
    // Defaults to 3.
    .with_max_attempts(CUSTOM_MAX_ATTEMPTS);
  
let config = aws_config::defaults(BehaviorVersion::latest())
    .retry_config(retry_config)
    .load()
    .await;
```

## Delays and backoff


If a retry is necessary, the default retry strategy waits before it makes the subsequent attempt. The delay for the first retry is small but it grows exponentially for later retries. The maximum amount of delay is capped so that it does not grow too large. 

Random jitter is applied to the delays between all attempts. The jitter helps mitigate the effect of large fleets that can cause retry storms. For a deeper discussion about exponential backoff and jitter, see [Exponential Backoff And Jitter](https://amazonaws-china.com/blogs/architecture/exponential-backoff-and-jitter/) in the *Amazon Architecture Blog*. 

 You can customize the delay settings in your code by supplying a modified [https://docs.rs/aws-smithy-types/latest/aws_smithy_types/retry/struct.RetryConfig.html](https://docs.rs/aws-smithy-types/latest/aws_smithy_types/retry/struct.RetryConfig.html) to your `aws_config::defaults`. The following code sets the configuration to delay the first retry attempt for up to 100 milliseconds and that the maximum amount of time between any retry attempt is 5 seconds. 

```
let retry_config = RetryConfig::standard()
    // Defaults to 1 second.
    .with_initial_backoff(Duration::from_millis(100))
    // Defaults to 20 seconds.
    .with_max_backoff(Duration::from_secs(5));
  
let config = aws_config::defaults(BehaviorVersion::latest())
    .retry_config(retry_config)
    .load() 
    .await;
```

## Adaptive Retry Mode


 As an alternative to the `standard` mode retry strategy, the `adaptive` mode retry strategy is an advanced approach that seeks the ideal request rate to minimize throttling errors. 

**Note**  
Adaptive retries is an advanced retry mode. Using this strategy is typically not recommended. See [Retry behavior](https://docs.amazonaws.cn/sdkref/latest/guide/feature-retry-behavior.html#standardvsadaptive) in the *Amazon SDKs and Tools Reference Guide*.

Adaptive retries includes all the features of standard retries. It adds a client-side rate limiter that measures the rate of throttled requests compared to non-throttled requests. It also limits traffic to attempt to stay within a safe bandwidth, ideally causing zero throttling errors. 

The rate adapts in real time to changing service conditions and traffic patterns and might increase or decrease the rate of traffic accordingly. Critically, the rate limiter might delay initial attempts in high-traffic scenarios. 

You can select the `adaptive` retry strategy in code by supplying a modified [https://docs.rs/aws-smithy-types/latest/aws_smithy_types/retry/struct.RetryConfig.html](https://docs.rs/aws-smithy-types/latest/aws_smithy_types/retry/struct.RetryConfig.html):

```
let config = aws_config::defaults(BehaviorVersion::latest())
    .retry_config(RetryConfig::adaptive())
    .load()
    .await;
```

# Configuring timeouts in the Amazon SDK for Rust
Timeouts

The Amazon SDK for Rust provides several settings for managing Amazon Web Services service request timeouts and stalled data streams. These help your application behave optimally when unexpected delays and failures occur in the network.

## API timeouts


When there are transient issues that could cause request attempts to take a long time or fail completely, it is important to review and set timeouts so that your application can fail fast and behave optimally. Requests that fail can be automatically retried by the SDK. It is a good practice to set timeouts for both the individual attempt and the entire request. 

The SDK for Rust provides a default timeout for establishing a connection for a request. The SDK doesn't have any default maximum wait-time set for recieving a response for a request attempt or for the entire request. The following timeout options are available:


| Parameter | Default value | Description | 
| --- | --- | --- | 
| Connect timeout | 3.1 seconds | The maximum amount of time to wait to establish a connection before giving up. | 
| Operation timeout | None | The maximum amount of time to wait before receiving a response from the SDK for Rust, including all retries. | 
| Operation attempt timeout | None | The maximum amount of time to wait for a single HTTP attempt, after which the API call can be retried. | 
| Read timeout | None | The maximum amount of time to wait to read the first byte of a response from the time the request is initiated. | 

The following example shows the configuration of an Amazon S3 client with custom timeout values:

```
let config = aws_config::defaults(BehaviorVersion::latest())
    .timeout_config(
        TimeoutConfig::builder()
            .operation_timeout(Duration::from_secs(5))
            .operation_attempt_timeout(Duration::from_millis(1500))
            .build()
    )
    .load()
    .await;

let s3 = aws_sdk_s3::Client::new(&config);
```

When you use both operation and attempt timeouts together, you set a hard limit on the total time spent on all attempts across retries. You also set an individual HTTP request to fail fast on a slow request.

As an alternative to setting these timeout values on the service client for all operations, you can configure or [override them for a single request](peroperation.md) .

**Important**  
Operation and attempt timeouts do not apply to streaming data consumed after the SDK for Rust has returned a response. As an example, consuming data from a `ByteStream` member of a response is not subject to operation timeouts.

## Stalled stream protection


The SDK for Rust provides another form of timeout related to detecting stalled streams. A stalled stream is an upload or download stream that produces no data for longer than a configured grace period. This helps prevent applications from hanging indefinitely and never making progress.

 Stalled stream protection will return an error when a stream is idle for longer than the acceptable period. 

By default, the SDK for Rust enables stalled stream protection for both uploads and downloads and looks for at least 1 byte/sec of activity with a generous grace period of 20 seconds.

The following example shows a customized `StalledStreamProtectionConfig` that disables upload protection and changes the grace period for no activity to 10 seconds:

```
let config = aws_config::defaults(BehaviorVersion::latest())
    .stalled_stream_protection(
        StalledStreamProtectionConfig::enabled()
            .upload_enabled(false)
            .grace_period(Duration::from_secs(10))
            .build()
    )
    .load()
    .await;
```

**Warning**  
Stalled stream protection is an advanced configuration option. We recommend altering these values only if your application needs tighter performance or if it is causing some other issue. 

### Disable stalled stream protection


The following example shows how to disable stalled stream protection completely:

```
let config = aws_config::defaults(BehaviorVersion::latest())
    .stalled_stream_protection(StalledStreamProtectionConfig::disabled())
    .load()
    .await;
```

# Configuring observability features in the Amazon SDK for Rust
Observability

 Observability is the extent to which a system's current state can be inferred from the data it emits. The data emitted is commonly referred to as telemetry.

**Topics**
+ [Logging](logging.md)

# Configuring and using logging in the Amazon SDK for Rust
Logging

The Amazon SDK for Rust uses the [tracing](http://tracing.rs/) framework for logging. To enable logging, add the `tracing-subscriber` crate and initialize it in your Rust application. Logs include timestamps, log levels, and module paths, helping debug API requests and SDK behavior. Use the `RUST_LOG` environment variable to control log verbosity, filtering by module if needed. 

## How to enable logging in the Amazon SDK for Rust


1. In a command prompt for your project directory, add the [tracing-subscriber](https://crates.io/crates/tracing-subscriber) crate as a dependency:

   ```
   $ cargo add tracing-subscriber --features tracing-subscriber/env-filter
   ```

   This adds the crate to the `[dependencies]` section of your `Cargo.toml` file.

1. Initialize the subscriber. Usually this is done early in the `main` function before calling any SDK for Rust operation:

   ```
   use aws_config::BehaviorVersion;
   
   type BoxError = Box<dyn Error + Send + Sync>;
   
   #[tokio::main]
   async fn main() -> Result<(), BoxError> {
       tracing_subscriber::fmt::init();  // Initialize the subscriber.
       
       let config = aws_config::defaults(BehaviorVersion::latest())
           .load()
           .await;
   
       let s3 = aws_sdk_s3::Client::new(&config);
   
       let _resp = s3.list_buckets()
           .send()
           .await?;
   
       Ok(())               
   }
   ```

1. Turn on logging using `RUST_LOG` environment variable. To enable the display of logging information, in a command prompt, set the `RUST_LOG` environment variable to the level you want to log at. The following example sets logging to the `debug` level:

------
#### [ Linux/macOS ]

   ```
   $ RUST_LOG=debug
   ```

------
#### [ Windows ]

   If you're using VSCode, the terminal window often defaults to PowerShell. Verify the type of prompt you are using.

   ```
   C:\> set RUST_LOG=debug
   ```

------
#### [ PowerShell ]

   ```
   PS C:\> $ENV:RUST_LOG="debug"
   ```

------

1. Run the program:

   ```
   $ cargo run
   ```

   You should see additional output in the console or terminal window.

For more information see [filtering events with environment variables](https://docs.rs/tracing-subscriber/0.3.18/tracing_subscriber/fmt/index.html#filtering-events-with-environment-variables) from the `tracing-subscriber` documentation.

## Interpret the log output
Interpret logs

Once you have turned on logging by following the steps in the previous section, additional log information will be printed to standard out by default. 

If you're using the default log output format (called "full" by the tracing module), the information that you see in the log output looks similar to this:

```
2024-06-25T16:10:12.367482Z DEBUG invoke{service=s3 operation=ListBuckets sdk_invocation_id=3434933}:try_op:try_attempt:lazy_load_identity: aws_smithy_runtime::client::identity::cache::lazy: identity cache miss occurred; added new identity (took 480.892ms) new_expiration=2024-06-25T23:07:59Z valid_for=25066.632521s partition=IdentityCachePartition(7)
2024-06-25T16:10:12.367602Z DEBUG invoke{service=s3 operation=ListBuckets sdk_invocation_id=3434933}:try_op:try_attempt: aws_smithy_runtime::client::identity::cache::lazy: loaded identity
2024-06-25T16:10:12.367643Z TRACE invoke{service=s3 operation=ListBuckets sdk_invocation_id=3434933}:try_op:try_attempt: aws_smithy_runtime::client::orchestrator::auth: resolved identity identity=Identity { data: Credentials {... }, expiration: Some(SystemTime { tv_sec: 1719356879, tv_nsec: 0 }) }
2024-06-25T16:10:12.367695Z TRACE invoke{service=s3 operation=ListBuckets sdk_invocation_id=3434933}:try_op:try_attempt: aws_smithy_runtime::client::orchestrator::auth: signing request
```

Each entry includes the following:
+ The log entry's timestamp.
+ The log level of the entry. This is a word such as `INFO`, `DEBUG`, or `TRACE`.
+ The nested set of [spans](https://docs.rs/tracing/latest/tracing/span/index.html) from which the log entry was generated, separated by colons (":"). This helps you identify the source of the log entry.
+ The Rust module path containing the code that generated the log entry.
+ The log message text.

The tracing module's standard output formats use ANSI escape codes to colorize the output. Keep these escape sequences in mind when filtering or searching the output.

**Note**  
The `sdk_invocation_id` that appears within the nested set of spans is a unique ID generated client side by the SDK to help correlate log messages. It is unrelated to the request ID found in the response from an Amazon Web Services service.

## Fine-tune your logging levels


If you use a crate that supports an environment filtering, such as `tracing_subscriber`, you can control the verbosity of logs by module.

You can turn on the same logging level for every module. The following sets the logging level to `trace` for every module: 

```
$ RUST_LOG=trace cargo run
```

You can turn on trace-level logging for a specific module. In the following example, only logs coming from `aws_smithy_runtime` will come in at `trace` level.

```
$ RUST_LOG=aws_smithy_runtime=trace
```

You can specify a different log level for multiple modules by separating them with commas. The following example sets the `aws_config` module to `trace` level logging, and the `aws_smithy_runtime` module to `debug` level logging. 

```
$ RUST_LOG=aws_config=trace,aws_smithy_runtime=debug cargo run
```

The following table describes some of the modules that you can use to filter log messages:


| Prefix | Description | 
| --- | --- | 
|  `aws_smithy_runtime`  |  Request and response wire logging  | 
|  `aws_config`  |  Credentials loading  | 
|  `aws_sigv4`  |  Request signing and canonical requests  | 

One way to figure out which modules you need to include in your log output is to first log everything, then find the crate name in the log output for the information you need. Then you can set the environment variable accordingly and run your program again.

# Configuring client endpoints in the Amazon SDK for Rust
Client endpoints

When the Amazon SDK for Rust calls an Amazon Web Services service, one of its first steps is to determine where to route the request. This process is known as endpoint resolution.

You can configure endpoint resolution for the SDK when you create a service client. The default configuration for endpoint resolution is usually fine, but there are several reasons why you might want to modify the default configuration. Two example reasons are as follows:
+ To make requests to a pre-release version of a service or to a local deployment of a service.
+ To access to specific service features not yet modeled in the SDK.

**Warning**  
Endpoint resolution is an advanced SDK topic. If you change the default settings, you risk breaking your code. The default settings apply to most users in production environments.

Custom endpoints can be set globally so that they are used for all service requests, or you can set a custom endpoint for a specific Amazon Web Services service.

Custom endpoints can be configured using environment variables or settings in the shared Amazon `config` file. For information on this approach, see [Service-specific endpoints](https://docs.amazonaws.cn/sdkref/latest/guide/feature-ss-endpoints.html) in the *Amazon SDKs and Tools Reference Guide*. For the complete list of shared `config` file settings and environment variables for all Amazon Web Services services, see [Identifiers for service-specific endpoints](https://docs.amazonaws.cn/sdkref/latest/guide/ss-endpoints-table.html).

 Alternatively, this customization can also be configured in your code, as shown in the following sections.

## Custom Configuration


You can customize endpoint resolution of a service client with two methods that are available when you build the client:

1. `endpoint_url(url: Into<String>)`

1. `endpoint_resolver(resolver: impl crate::config::endpoint::ResolveEndpoint + `static)`

You can set both properties. However, most often you provide only one. For general usage, `endpoint_url` is most frequently customized.

### Set endpoint URL


You can set a value for `endpoint_url` to indicate a "base" hostname for the service. This value, however, is not final since it is passed as a parameter to the client's `ResolveEndpoint` instance. The `ResolveEndpoint` implementation can then inspect and potentially modify that value to determine the final endpoint.

### Set endpoint resolver


A service client's `ResolveEndpoint` implementation determines the final resolved endpoint that the SDK uses for any given request. A service client calls the `resolve_endpoint` method for every request and uses the [https://docs.rs/aws-smithy-runtime-api/latest/aws_smithy_runtime_api/client/endpoint/struct.EndpointFuture.html](https://docs.rs/aws-smithy-runtime-api/latest/aws_smithy_runtime_api/client/endpoint/struct.EndpointFuture.html) value that is returned by the resolver with no further changes.

The following example demonstrates supplying a custom endpoint resolver implementation for an Amazon S3 client that resolves a different endpoint per-stage, such as staging and production:

```
use aws_sdk_s3::config::endpoint::{ResolveEndpoint, EndpointFuture, Params, Endpoint};

#[derive(Debug)]
struct StageResolver { stage: String }
impl ResolveEndpoint for StageResolver {
    fn resolve_endpoint(&self, params: &Params) -> EndpointFuture<'_> {
        let stage = &self.stage;
        EndpointFuture::ready(Ok(Endpoint::builder().url(format!("{stage}.myservice.com")).build()))
    }
}


let config = aws_config::defaults(BehaviorVersion::latest())
    .load()
    .await;

let resolver = StageResolver { stage: std::env::var("STAGE").unwrap() };

let s3_config = aws_sdk_s3::config::Builder::from(&config)
    .endpoint_resolver(resolver)
    .build();

let s3 = aws_sdk_s3::Client::from_conf(s3_config);
```

**Note**  
Endpoint resolvers, and by extension the `ResolveEndpoint` trait, are specific to each service, and thus can only be configured on the service client config. Endpoint URL, on the other hand, can be configured either using shared config (applying to all services derived from it) or for a specific service.

#### ResolveEndpoint parameters


The `resolve_endpoint` method accepts service-specific parameters that contain properties used in endpoint resolution.

Every service includes the following base properties:


| Name | Type | Description | 
| --- | --- | --- | 
| region | String | The client's Amazon Web Services Region | 
| endpoint | String | A string representation of the value set of endpointUrl | 
| use\$1fips | Boolean | Whether FIPS endpoints are enabled in the client's configuration | 
| use\$1dual\$1stack | Boolean | Whether dual-stack endpoints are enabled in the client's configuration | 

Amazon Web Services services can specify additional properties required for resolution. For example, Amazon S3 [endpoint parameters](https://docs.rs/aws-sdk-s3/latest/aws_sdk_s3/config/endpoint/struct.Params.html) includes the bucket name and also several Amazon S3-specific feature settings. For example, the `force_path_style` property determines whether virtual host addressing can be used.

If you implement your own provider, you shouldn't need to construct your own instance of endpoint parameters. The SDK provides the properties for each request and passes them to your implementation of `resolve_endpoint`.

### Compare using `endpoint_url` to using `endpoint_resolver`


It is important to understand that the following two configurations, one that uses `endpoint_url` and the other that uses `endpoint_resolver`, do NOT produce clients with equivalent endpoint resolution behavior.

```
use aws_sdk_s3::config::endpoint::{ResolveEndpoint, EndpointFuture, Params, Endpoint};

#[derive(Debug, Default)]
struct CustomResolver;
impl ResolveEndpoint for CustomResolver {
    fn resolve_endpoint(&self, _params: &Params) -> EndpointFuture<'_> {
        EndpointFuture::ready(Ok(Endpoint::builder().url("https://endpoint.example").build()))
    }
}

let config = aws_config::defaults(BehaviorVersion::latest())
    .load()
    .await;

// use endpoint url
aws_sdk_s3::config::Builder::from(&config)
    .endpoint_url("https://endpoint.example")
    .build();
    
// Use endpoint resolver
aws_sdk_s3::config::Builder::from(&config)
    .endpoint_resolver(CustomResolver::default())
    .build();
```

The client that sets the `endpoint_url` specifies a *base* URL that is passed to the (default) provider, that can be modified as part of endpoint resolution.

The client that sets the `endpoint_resolver` specifies the *final* URL the Amazon S3 client uses.

## Examples


Custom endpoints are often used for testing. Instead of making calls out to the cloud-based service, calls are routed to a locally-hosted, simulated service. Two such options are:
+ [DynamoDB local](https://docs.amazonaws.cn/amazondynamodb/latest/developerguide/DynamoDBLocal.html) – a local version of the Amazon DynamoDB service.
+ [LocalStack](https://github.com/localstack/localstack) – a cloud service emulator that runs in a container on your local machine.

 The following examples illustrate two different ways to specify a custom endpoint to use these two testing options.

### Use DynamoDB local directly in code


As described in the previous sections, you can set `endpoint_url` directly in code to override the base endpoint to point to the local DynamoDB server. In your code:

```
    let config = aws_config::defaults(aws_config::BehaviorVersion::latest())
        .test_credentials()
        // DynamoDB run locally uses port 8000 by default.
        .endpoint_url("http://localhost:8000")
        .load()
        .await;
    let dynamodb_local_config = aws_sdk_dynamodb::config::Builder::from(&config).build();

    let client = aws_sdk_dynamodb::Client::from_conf(dynamodb_local_config);
```

The [complete example](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/rustv1/examples/dynamodb/src/bin/list-tables-local.rs) is available on GitHub.

### Use LocalStack using the `config` file


You can set [service-specific endpoints](https://docs.amazonaws.cn/sdkref/latest/guide/feature-ss-endpoints.html) in your shared Amazon `config` file. The following configuration profile sets `endpoint_url` to connect to `localhost` on port `4566`. For more information on LocalStack configuration, see [Accessing LocalStack via the endpoint URL](https://docs.localstack.cloud/references/network-troubleshooting/endpoint-url/) on the *LocalStack docs* website.

```
[profile localstack]
region=us-east-1
endpoint_url = http://localhost:4566
```

The SDK will pick up the changes in the shared `config` file and apply them to your SDK clients when you use the `localstack` profile. Using this approach, your code doesn't need to include any reference to endpoints, and would look like:

```
    // set the environment variable `AWS_PROFILE=localstack` when running
    // the application to source `endpoint_url` and point the SDK at the
    // localstack instance
    let config = aws_config::defaults(BehaviorVersion::latest()).load().await;

    let s3_config = aws_sdk_s3::config::Builder::from(&config)
        .force_path_style(true)
        .build();

    let s3 = aws_sdk_s3::Client::from_conf(s3_config);
```

The [complete example](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/rustv1/examples/localstack) is available on GitHub.

# Overriding a single operation configuration of a client in the Amazon SDK for Rust
Overriding an operation configuration

After you [create a service client](config-code.md), configuration becomes immutable and will apply to all subsequent operations. While configuration can’t be modified at this point, it can be overridden on a per-operation basis. 

Each operation builder has a `customize` method available to create a `CustomizableOperation` so that you can override an individual copy of the existing configuration. The original client configuration will remain unmodified. 

The following example shows the creation of an Amazon S3 client that calls two operations, the second of which is overridden to send to a different Amazon Web Services Region. All of Amazon S3's object invocations use the `us-east-1` region except for when the API call is explicitly overridden to use the modified `us-west-2`.

```
use aws_config::{BehaviorVersion, Region};

let config = aws_config::defaults(BehaviorVersion::latest())
    .region("us-east-1")
    .load()
    .await;

let s3 = aws_sdk_s3::Client::new(&config);

// Request will be sent to "us-east-1"
s3.list_buckets()
    .send()
    .await?;

// Unset fields default to using the original config value
let modified = aws_sdk_s3::Config::builder()
    .region(Region::from_static("us-west-2"));

// Request will be sent to "us-west-2"
s3.list_buckets()
   // Creates a CustomizableOperation
    .customize()
    .config_override(modified)
    .send()
    .await?;
```

**Note**  
The previous example is for Amazon S3, however the concept is the same for all operations. Certain operations might have additional methods on `CustomizeableOperation`.

For an example of adding an interceptor using `customize` for a single operation, see [Interceptor for only a specific operation](interceptors.md#interceptors-registration-specific). 

# Configuring HTTP-level settings within the Amazon SDK for Rust
HTTP

The Amazon SDK for Rust provides built-in HTTP functionality that is used by the Amazon Web Services service clients that you create in your code. 

By default, the SDK for Rust uses an HTTPS client based on `hyper`, `rustls`, and `aws-lc-rs`. This client should work well for most use cases without additional configuration. 
+ [https://docs.rs/hyper/latest/hyper/](https://docs.rs/hyper/latest/hyper/) is a lower-level HTTP library for Rust that can be used with the Amazon SDK for Rust to make API service calls.
+ [https://github.com/rustls/rustls](https://github.com/rustls/rustls) is a modern TLS library written in Rust that has built-in options for cryptographic providers.
+ [https://github.com/aws/aws-lc](https://github.com/aws/aws-lc) is a general-purpose cryptographic library containing algorithms needed for TLS and common applications. 
+ [https://github.com/aws/aws-lc-rs](https://github.com/aws/aws-lc-rs) is an idiomatic wrapper around the `aws-lc` library in Rust.

The `aws-smithy-http-client` crate provides some additional options and configuration if you want to choose a different TLS or cryptographic provider. For more advanced use cases you are encouraged to bring your own HTTP client implementation or file a feature request for consideration.

## Choosing an alternative TLS provider


The `aws-smithy-http-client` crate provides a few alternative TLS providers.

The following providers are available:

**`rustls` with `aws-lc`**  
A TLS provider based on [https://github.com/rustls/rustls](https://github.com/rustls/rustls) that uses [https://github.com/aws/aws-lc-rs](https://github.com/aws/aws-lc-rs) for cryptography.  
This is the default HTTP behavior for the SDK for Rust. If you want to use this option you don't need to take any additional action in your code.

**`s2n-tls`**  
A TLS provider based on [https://github.com/aws/s2n-tls](https://github.com/aws/s2n-tls).

**`rustls` with `aws-lc-fips`**  
A TLS provider based on [https://github.com/rustls/rustls](https://github.com/rustls/rustls) that uses a FIPS-compliant version of [https://github.com/aws/aws-lc-rs](https://github.com/aws/aws-lc-rs) for cryptography

**`rustls` with `ring`**  
A TLS provider based on [https://github.com/rustls/rustls](https://github.com/rustls/rustls) that uses [https://github.com/briansmith/ring](https://github.com/briansmith/ring) for cryptography.

### Prerequisites


Using `aws-lc-rs` or `s2n-tls` requires a C Compiler (Clang or GCC) to build. For some platforms, the build may also require CMake. Building with the "fips" feature on any platform requires CMake and Go. For more information, reference the [AWS Libcrypto for Rust (`aws-lc-rs`)](https://github.com/aws/aws-lc-rs/blob/main/aws-lc-rs/README.md) repository and build instructions.

### How to use an alternative TLS provider


The `aws-smithy-http-client` crate provides additional TLS options. For your Amazon Web Services service clients to use a different TLS provider, override the `http_client` using the loader from the `aws_config` crate. The HTTP client is used for both Amazon Web Services services and credentials providers.

The following example shows how to use the `s2n-tls` TLS provider. However, a similar approach works for other providers as well.

To compile the example code, run the following command to add dependencies to your project:

```
cargo add aws-smithy-http-client -F s2n-tls
```

Example code:

```
use aws_smithy_http_client::{tls, Builder};

#[tokio::main]
async fn main() {
    let http_client = Builder::new()
        .tls_provider(tls::Provider::S2nTls)
        .build_https();

    let sdk_config = aws_config::defaults(
        aws_config::BehaviorVersion::latest()
    )
    .http_client(http_client)
    .load()
    .await;

    // create client(s) using sdk_config
    // e.g. aws_sdk_s3::Client::new(&sdk_config);
}
```

## Enabling FIPS support


The `aws-smithy-http-client` crate provides an option to enable a FIPS-compliant crypto implementation. For your Amazon Web Services service clients to use the FIPS-compliant provider, override the `http_client` using the loader from the `aws_config` crate. The HTTP client is used for both Amazon Web Services services and credentials providers.

**Note**  
FIPS support requires additional dependencies in your build environment. See the [build](https://github.com/aws/aws-lc/blob/main/BUILDING.md) instructions for the `aws-lc` crate.

To compile the example code, run the following command to add dependencies to your project:

```
cargo add aws-smithy-http-client -F rustls-aws-lc-fips
```

The following example code enables FIPS support:

```
// file: main.rs
use aws_smithy_http_client::{
    tls::{self, rustls_provider::CryptoMode},
    Builder,
};

#[tokio::main]
async fn main() {
    let http_client = Builder::new()
        .tls_provider(tls::Provider::Rustls(CryptoMode::AwsLcFips))
        .build_https();

    let sdk_config = aws_config::defaults(
        aws_config::BehaviorVersion::latest()
    )
    .http_client(http_client)
    .load()
    .await;

    // create client(s) using sdk_config
    // e.g. aws_sdk_s3::Client::new(&sdk_config);
}
```

## Prioritizing post-quantum key exchange


The default TLS provider is based on `rustls` using `aws-lc-rs` which supports the `X25519MLKEM768` post-quantum key exchange algorithm. To make `X25519MLKEM768` the highest priority algorithm you need to add the `rustls` package to your crate and enable the `prefer-post-quantum` feature flag. Otherwise, it is available but not the highest priority. See the `rustls` [documentation](https://docs.rs/rustls/0.23.23/rustls/manual/_05_defaults/index.html#about-the-post-quantum-secure-key-exchange-x25519mlkem768) for more information. 

**Note**  
This will become the default in a future release.

## Overriding the DNS Resolver


 The default DNS resolver can be overridden by configuring the HTTP client manually. 

To compile the example code, run the following commands to add dependencies to your project:

```
cargo add aws-smithy-http-client -F rustls-aws-lc
cargo add aws-smithy-runtime-api -F client
```

The following example code overrides the DNS resolver:

```
use aws_smithy_http_client::{
    tls::{self, rustls_provider::CryptoMode},
    Builder
};
use aws_smithy_runtime_api::client::dns::{DnsFuture, ResolveDns};
use std::net::{IpAddr, Ipv4Addr};

/// A DNS resolver that returns a static IP address (127.0.0.1)
#[derive(Debug, Clone)]
struct StaticResolver;

impl ResolveDns for StaticResolver {
    fn resolve_dns<'a>(&'a self, _name: &'a str) -> DnsFuture<'a> {
        DnsFuture::ready(Ok(vec![IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))]))
    }
}

#[tokio::main]
async fn main() {
    let http_client = Builder::new()
        .tls_provider(tls::Provider::Rustls(CryptoMode::AwsLc))
        .build_with_resolver(StaticResolver);
    
    let sdk_config = aws_config::defaults(
        aws_config::BehaviorVersion::latest()
    )
    .http_client(http_client)
    .load()
    .await;
    
    // create client(s) using sdk_config
    // e.g. aws_sdk_s3::Client::new(&sdk_config);
}
```

**Note**  
By default, Amazon Linux 2023 (AL2023) doesn’t cache DNS on the operating system level.

## Customizing root CA certificates


By default, the TLS provider loads the system native root certificates for the given platform. To customize this behavior to load a custom CA bundle, you can configure a `TlsContext` with your own `TrustStore`. 

To compile the example code, run the following commands to add dependencies to your project:

```
cargo add aws-smithy-http-client -F rustls-aws-lc
```

The following example uses `rustls` with `aws-lc` but will work for any supported TLS provider: 

```
use aws_smithy_http_client::{
    tls::{self, rustls_provider::CryptoMode},
    Builder
};
use std::fs;

/// read the PEM encoded root CA (bundle) and return a custom TLS context
fn tls_context_from_pem(filename: &str) -> tls::TlsContext {
    let pem_contents = fs::read(filename).unwrap();
    
    // Create a new empty trust store (this will not load platform native certificates)
    let trust_store = tls::TrustStore::empty()
        .with_pem_certificate(pem_contents.as_slice());
        
    tls::TlsContext::builder()
        .with_trust_store(trust_store)
        .build()
        .expect("valid TLS config")
}

#[tokio::main]
async fn main() {
    let http_client = Builder::new()
        .tls_provider(tls::Provider::Rustls(CryptoMode::AwsLc))
        .tls_context(tls_context_from_pem("my-custom-ca.pem"))
        .build_https();
    
    let sdk_config = aws_config::defaults(
        aws_config::BehaviorVersion::latest()
    )
    .http_client(http_client)
    .load()
    .await;
    
    // create client(s) using sdk_config
    // e.g. aws_sdk_s3::Client::new(&sdk_config);
}
```

# Configuring interceptors in the Amazon SDK for Rust
Interceptors

You can use interceptors to hook into the execution of API requests and responses. Interceptors are open-ended mechanisms in which the SDK calls code that you write to inject behavior into the request/response lifecycle. This way, you can modify an in-flight request, debug request processing, view errors, and more. 

The following example shows a simple interceptor that adds an additional header to all outgoing requests before the retry loop is entered:

```
use std::borrow::Cow;
use aws_smithy_runtime_api::client::interceptors::{
    Intercept,
    context::BeforeTransmitInterceptorContextMut,   
};
use aws_smithy_runtime_api::client::runtime_components::RuntimeComponents;
use aws_smithy_types::config_bag::ConfigBag;
use aws_smithy_runtime_api::box_error::BoxError;

#[derive(Debug)]
struct AddHeaderInterceptor {
    key: Cow<'static, str>,
    value: Cow<'static, str>,
}

impl AddHeaderInterceptor {
    fn new(key: &'static str, value: &'static str) -> Self {
        Self {
            key: Cow::Borrowed(key),
            value: Cow::Borrowed(value),
        }
    }
}

impl Intercept for AddHeaderInterceptor {
    fn name(&self) -> &'static str {
        "AddHeader"
    }

    fn modify_before_retry_loop(
        &self,
        context: &mut BeforeTransmitInterceptorContextMut<'_>,
        _runtime_components: &RuntimeComponents,
        _cfg: &mut ConfigBag,
    ) -> Result<(), BoxError> {
        let headers = context.request_mut().headers_mut();
        headers.insert(self.key.clone(), self.value.clone());

        Ok(())
    }
}
```

For more information and the available interceptor hooks, see the [Intercept](https://docs.rs/aws-smithy-runtime-api/latest/aws_smithy_runtime_api/client/interceptors/trait.Intercept.html) trait.

## Interceptor registration


You register interceptors when you construct a service client or when you override configuration for a specific operation. The registration in different depending on whether you want the interceptor to apply to all operations for your client or only specific ones.

### Interceptor for all operations on a service client


To register an interceptor for the entire client, add the interceptor using the `Builder` pattern.

```
let config = aws_config::defaults(BehaviorVersion::latest())
    .load()
    .await;
    
// All service operations invoked using 's3' will have the header added.
let s3_conf = aws_sdk_s3::config::Builder::from(&config)
    .interceptor(AddHeaderInterceptor::new("x-foo-version", "2.7"))
    .build();

let s3 = aws_sdk_s3::Client::from_conf(s3_conf);
```

### Interceptor for only a specific operation


To register an interceptor for only a single operation, use the `customize` extension. You can override your service client configurations at the per-operation level using this method. For more information on customizable operations, see [Overriding a single operation configuration of a client in the Amazon SDK for Rust](peroperation.md).

```
// Only the list_buckets operation will have the header added.
s3.list_buckets()
    .customize()
    .interceptor(AddHeaderInterceptor::new("x-bar-version", "3.7"))
    .send()
    .await?;
```