Configuring Client Endpoints

Customizing service client endpoints.

The AWS SDK for Go V2 provides the ability to configure a custom endpoint to be used for a service. In most cases you use a pre-configured endpoint for a service. Configuring custom endpoints, lets you do more, such as working with pre-release versions of a service.

A EndpointResolver can be configured to provide custom endpoint resolution logic for service clients. You can use a custom endpoint resolver to override a service’s endpoint resolution logic for all endpoints, or a just specific regional endpoint. Custom endpoint resolver can trigger the service’s endpoint resolution logic to fallback if a custom resolver does not wish to resolve a requested endpoint. EndpointResolverFunc can be used to easily wrap functions to satisfy the EndpointResolver interface.

A EndpointResolver can be easily configured by passing the resolver wrapped with WithEndpointResolver to LoadDefaultConfig, allowing for the ability to override endpoints when loading credentials, as well as configuring the resulting aws.Config with your custom endpoint resolver.

The endpoint resolver is given the service and region as a string, allowing for the resolver to dynamically drive its behavior. Each service client package has an exported ServiceID constant which can be used to determine which service client is invoking your endpoint resolver.

An endpoint resolver can use the EndpointNotFoundError sentinel error value to trigger fallback resolution to the service clients default resolution logic. This allows you to selectively override one or more endpoints seamlessly without having to handle fallback logic.

If your endpoint resolver implementation returns an error other than EndpointNotFoundError, endpoint resolution will stop and the service operation returns an error to your application.

Examples

Overriding Endpoint with Fallback

The following code snippet shows how a single service endpoint can be overridden for DynamoDB with fallback behavior for other endpoints:

customResolver := aws.EndpointResolverFunc(func(service, region string) (aws.Endpoint, error) {
    if service == dynamodb.ServiceID && region == "us-west-2" {
        return aws.Endpoint{
            PartitionID:   "aws",
            URL:           "https://test.us-west-2.amazonaws.com",
            SigningRegion: "us-west-2",
        }, nil
    }
    // returning EndpointNotFoundError will allow the service to fallback to it's default resolution
    return aws.Endpoint{}, &aws.EndpointNotFoundError{}
})

cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithEndpointResolver(customResolver))

Overriding Endpoint Without Fallback

The following code snippet shows how a single service endpoint can be overridden for DynamoDB without fallback behavior for other endpoints:

customResolver := aws.EndpointResolverFunc(func(service, region string) (aws.Endpoint, error) {
    if service == dynamodb.ServiceID && region == "us-west-2" {
        return aws.Endpoint{
            PartitionID:   "aws",
            URL:           "https://test.us-west-2.amazonaws.com",
            SigningRegion: "us-west-2",
        }, nil
    }
    return aws.Endpoint{}, fmt.Errorf("unknown endpoint requested")
})

cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithEndpointResolver(customResolver))

Immutable Endpoints

Setting an endpoint as immutable may prevent some service client features from functioning correctly, and could result in undefined behavior. Caution should be taken when defining an endpoint as immutable.

Some service clients, such as Amazon S3, may modify the endpoint returned by the resolver for certain service operations. For example, the Amazon S3 will automatically handle Virtual Bucket Addressing by mutating the resolved endpoint. You can prevent the SDK from mutating your custom endpoints by setting HostnameImmutable totrue. For example:

customResolver := aws.EndpointResolverFunc(func(service, region string) (aws.Endpoint, error) {
    if service == dynamodb.ServiceID && region == "us-west-2" {
        return aws.Endpoint{
            PartitionID:   "aws",
            URL:           "https://test.us-west-2.amazonaws.com",
            SigningRegion: "us-west-2",
            HostnameImmutable: true,
        }, nil
    }
    return aws.Endpoint{}, fmt.Errorf("unknown endpoint requested")
})

cfg, err := config.LoadDefaultConfig(context.TODO(), config.WithEndpointResolver(customResolver))