クライアントエンドポイントを設定する - AWS SDK for Go v2

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

クライアントエンドポイントを設定する

警告

エンドポイントの解決は上級者向けの SDK トピックです。これらの設定を変更すると、コードが動作しなくなる可能性があります。デフォルト設定は、本番環境のほとんどのユーザーに適しています。

AWS SDK for Go では、サービスで使用するカスタムエンドポイントを設定できます。ほとんどの場合、デフォルトの設定で十分です。カスタムエンドポイントを設定することで、サービスのプレリリースバージョンとの連携など、追加の動作が可能になります。

カスタマイズ

SDK では、エンドポイント解決の設定に 2 つの「バージョン」があります。

  • v2。2023 年第 3 四半期にリリース。以下で設定:

    • EndpointResolverV2

    • BaseEndpoint

  • v1。SDK と同時にリリース。以下で設定:

    • EndpointResolver

新しいエンドポイント関連のサービス機能にアクセスできるようにするため、v1 エンドポイント解決のユーザーは v2 に移行することをお勧めします。

V2: EndpointResolverV2 + BaseEndpoint

エンドポイント解決 v2 では、EndpointResolverV2 がエンドポイント解決の決定的なメカニズムです。リゾルバーの ResolveEndpoint メソッドは、SDK で行うすべてのリクエストのワークフローの一部として呼び出されます。リゾルバーが返す Endpoint のホスト名はリクエスト時にそのまま使用されます (ただし、オペレーションシリアライザが HTTP パスに追記することはできます)。

エンドポイント解決 v2 では、クライアントレベルの追加設定 BaseEndpoint が含まれており、サービスインスタンスの「ベース」ホスト名を指定するために使用されます。ここで設定された値は決定的なものではなく、最終的にはクライアントの EndpointResolverV2 にパラメータとして渡され、最終解決に使用されます (EndpointResolverV2 パラメータの詳細については後述)。その後、リゾルバーの実装により、この値が検査 (場合によっては変更) されて、最終的なエンドポイントが決定されます。

例えば、BaseEndpoint を指定したクライアントで、特定のバケットに対して S3 GetObject リクエストを実行する場合、デフォルトのリゾルバーは、バケットが仮想ホスト対応であればホスト名にバケット名を挿入します (クライアント設定で仮想ホスティングを無効にしていない場合)。

実際には、BaseEndpoint はほとんどの場合、クライアントの接続先を開発インスタンスやプレビューインスタンスに指定するために使用されます。

EndpointResolverV2 個のパラメータ

各サービスは、それぞれ専用の入力値セットを受け取り、それを EndpointParameters としてサービスパッケージ内で定義された解決関数に渡します。

すべてのサービスには、AWS 内での一般的なエンドポイント解決を容易にする次の基本パラメータが含まれています。

名前 type description
Region string クライアントの AWS リージョン
Endpoint string クライアント設定での BaseEndpoint の値
UseFips bool クライアント設定で FIPS エンドポイントが有効かどうか
UseDualStack bool クライアント設定でデュアルスタックエンドポイントが有効かどうか

サービスは、エンドポイント解決に必要な追加のパラメータを指定できます。例えば、S3 の EndpointParameters にはバケット名や、仮想ホストアドレッシングが有効かどうかなど、S3 固有の機能設定が含まれます。

独自の EndpointResolverV2 を実装する場合でも、EndpointParameters のインスタンスを自分で作成する必要はありません。SDK がリクエストごとにそれらの値を取得し、カスタム実装に渡します。

Amazon S3 に関する注意事項

Amazon S3 は、バケットの仮想ホスティングや S3 MRAP など、複雑なエンドポイントのカスタマイズによって多くの機能が設計されている高度なサービスです。

このため、S3 クライアントの EndpointResolverV2 実装を置き換えないことをお勧めします。エンドポイントの追加設定を行ったローカル開発スタックにリクエストを送信するなど、解決動作を拡張する場合は、デフォルトの実装をラップし、その中で必要に応じて元の実装に処理を委譲 (フォールバック) することをお勧めします (以下の例を参照)。

BaseEndpoint の場合

次のコードスニペットでは、S3 クライアントの接続先をローカルのサービスインスタンス (この例ではループバックデバイスのポート 8080) に指定する方法を示しています。

client := s3.NewFromConfig(cfg, func (o *svc.Options) { o.BaseEndpoint = aws.String("https://localhost:8080/") })

EndpointResolverV2 の場合

次のコードスニペットでは、EndpointResolverV2 を使用して S3 のエンドポイント解決にカスタム動作を挿入する方法を示しています。

import ( "context" "net/url" "github.com/aws/aws-sdk-go-v2/service/s3" smithyendpoints "github.com/aws/smithy-go/endpoints" ) type resolverV2 struct { // you could inject additional application context here as well } func (*resolverV2) ResolveEndpoint(ctx context.Context, params s3.EndpointParameters) ( smithyendpoints.Endpoint, error, ) { if /* input params or caller context indicate we must route somewhere */ { u, err := url.Parse("https://custom.service.endpoint/") if err != nil { return smithyendpoints.Endpoint{}, err } return smithyendpoints.Endpoint{ URI: *u, }, nil } // delegate back to the default v2 resolver otherwise return s3.NewDefaultEndpointResolverV2().ResolveEndpoint(ctx, params) } func main() { // load config... client := s3.NewFromConfig(cfg, func (o *s3.Options) { o.EndpointResolverV2 = &resolverV2{ // ... } }) }

両方を使用

次のサンプルプログラムでは、BaseEndpointEndpointResolverV2 の相互動作を示しています。これは、高度なユースケースです。

import ( "context" "fmt" "log" "net/url" "github.com/aws/aws-sdk-go-v2" "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/service/s3" smithyendpoints "github.com/aws/smithy-go/endpoints" ) type resolverV2 struct {} func (*resolverV2) ResolveEndpoint(ctx context.Context, params s3.EndpointParameters) ( smithyendpoints.Endpoint, error, ) { // s3.Options.BaseEndpoint is accessible here: fmt.Printf("The endpoint provided in config is %s\n", *params.Endpoint) // fallback to default return s3.NewDefaultEndpointResolverV2().ResolveEndpoint(ctx, params) } func main() { cfg, err := config.LoadDefaultConfig(context.Background()) if (err != nil) { log.Fatal(err) } client := s3.NewFromConfig(cfg, func (o *s3.Options) { o.BaseEndpoint = aws.String("https://endpoint.dev/") o.EndpointResolverV2 = &resolverV2{} }) // ignore the output, this is just for demonstration client.ListBuckets(context.Background(), nil) }

このプログラムを実行すると、次の出力が得られます。

The endpoint provided in config is https://endpoint.dev/

V1: EndpointResolver

警告

エンドポイント解決 v1 は下位互換性のために保持されており、v2 の最新の動作とは分離されています。呼び出し元が EndpointResolver フィールドを設定した場合にのみ使用されます。

v1 を使用すると、v2 リリース以降に導入されたエンドポイント関連のサービス機能にアクセスできなくなる可能性が高くなります。アップグレード方法の手順については、「移行」を参照してください。

EndpointResolver を設定することで、サービスクライアントにカスタムエンドポイント解決ロジックを提供できます。カスタムエンドポイントリゾルバーを使用して、すべてのエンドポイント、または特定のリージョンエンドポイントに対して、サービスのエンドポイント解決ロジックをオーバーライドできます。カスタムエンドポイントリゾルバーが、あるエンドポイントの解決を行わない場合 (意図的にスキップする場合など)、サービスのエンドポイント解決ロジックにフォールバックさせることができます。EndpointResolverWithOptionsFunc を使用すると、関数を簡単にラップして EndpointResolverWithOptions インターフェイスを実装できます。

EndpointResolver は、WithEndpointResolverWithOptions でラップされたリゾルバーを LoadDefaultConfig に渡すことで簡単に設定でき、認証情報のロード時にエンドポイントをオーバーライドしたり、結果として得られる aws.Config にカスタムエンドポイントリゾルバーを設定したりできます。

エンドポイントリゾルバーにはサービス名とリージョンが文字列として渡されるため、リゾルバーはその動作を動的に制御できます。各サービスクライアントパッケージには、どのサービスクライアントがエンドポイントリゾルバーを呼び出しているかを特定するための ServiceID 定数がエクスポートされています。

エンドポイントリゾルバーは、EndpointNotFoundError のセンチネルエラー値を使用して、サービスクライアントのデフォルト解決ロジックにフォールバックさせます。これにより、フォールバックロジックを個別に扱うことなく、1 つ以上のエンドポイントを選択的にシームレスにオーバーライドできます。

エンドポイントリゾルバーが EndpointNotFoundError 以外のエラーを返した場合、エンドポイント解決は停止し、サービスオペレーションはアプリケーションにエラーを返します。

フォールバックあり

DynamoDB の 1 つのサービスエンドポイントをオーバーライドし、他のエンドポイントにはフォールバック動作を適用する方法を示すコードスニペットです。

customResolver := aws.EndpointResolverWithOptionsFunc(func(service, region string, options ...interface{}) (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.WithEndpointResolverWithOptions(customResolver))

フォールバックなし

DynamoDB の 1 つのサービスエンドポイントをオーバーライドし、他のエンドポイントにはフォールバック動作を適用しない方法を示すコードスニペットです。

customResolver := aws.EndpointResolverWithOptionsFunc(func(service, region string, options ...interface{}) (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.WithEndpointResolverWithOptions(customResolver))

変更不可のエンドポイント

警告

エンドポイントを変更不可として設定すると、一部のサービスクライアント機能が正しく動作しなくなり、未定義の動作が発生する可能性があります。エンドポイントを変更不可として定義する際は注意が必要です。

Amazon S3 などの一部のサービスクライアントでは、特定のサービスオペレーションに対してリゾルバーが返すエンドポイントを変更する場合があります。例えば Amazon S3 では、仮想バケットアドレス指定を自動的に処理するために、解決されたエンドポイントを変更します。HostnameImmutabletrue に設定することで、SDK がカスタムエンドポイントを変更しないようにできます。例:

customResolver := aws.EndpointResolverWithOptionsFunc(func(service, region string, options ...interface{}) (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.WithEndpointResolverWithOptions(customResolver))

移行

エンドポイント解決を v1 から v2 に移行する際は、次の一般的な原則が適用されます。

  • HostnameImmutablefalse に設定した Endpoint を返すことは、BaseEndpoint を v1 から元々返された URL に設定し、EndpointResolverV2 をデフォルトのままにすることとほぼ同等です。

  • HostnameImmutable を true に設定した Endpoint を返すことは、v1 から元々返された URL を返す EndpointResolverV2 を実装することとほぼ同等です。

    • 主な例外は、エンドポイントのプレフィックスがモデルとして定義されているオペレーションに該当する場合です。これに関する注意点は後述します。

これらのケースの例を次に示します。

警告

v1 の変更不可エンドポイントと v2 の解決ロジックは、動作上は同等ではありません。例えば、S3 Object Lambda などのカスタム機能に対する署名のオーバーライドは、v1 コードで返された変更不可エンドポイントには適用されますが、v2 では適用されません。

ホストプレフィックスに関する注意事項

一部のオペレーションでは、解決されたエンドポイントの前にホストプレフィックスが付加されます。この動作は ResolveEndpointV2 の出力と連携して機能する必要があるため、ホストプレフィックスはその結果に引き続き適用されます。

ミドルウェアを適用することで、エンドポイントホストのプレフィックスを手動で無効にできます (例のセクションを参照)。

変更可能なエンドポイント

次のコードサンプルは、変更可能なエンドポイントを返す基本的な v1 エンドポイントリゾルバーをどのように移行するかを示しています。

// v1 client := svc.NewFromConfig(cfg, func (o *svc.Options) { o.EndpointResolver = svc.EndpointResolverFromURL("https://custom.endpoint.api/") }) // v2 client := svc.NewFromConfig(cfg, func (o *svc.Options) { // the value of BaseEndpoint is passed to the default EndpointResolverV2 // implementation, which will handle routing for features such as S3 accelerate, // MRAP, etc. o.BaseEndpoint = aws.String("https://custom.endpoint.api/") })

変更不可のエンドポイント

// v1 client := svc.NewFromConfig(cfg, func (o *svc.Options) { o.EndpointResolver = svc.EndpointResolverFromURL("https://custom.endpoint.api/", func (e *aws.Endpoint) { e.HostnameImmutable = true }) }) // v2 import ( smithyendpoints "github.com/aws/smithy-go/endpoints" ) type staticResolver struct {} func (*staticResolver) ResolveEndpoint(ctx context.Context, params svc.EndpointParameters) ( smithyendpoints.Endpoint, error, ) { // This value will be used as-is when making the request. u, err := url.Parse("https://custom.endpoint.api/") if err != nil { return smithyendpoints.Endpoint{}, err } return smithyendpoints.Endpoint{ URI: *u, }, nil } client := svc.NewFromConfig(cfg, func (o *svc.Options) { o.EndpointResolverV2 = &staticResolver{} })

ホストプレフィックスを無効にする

import ( "context" "fmt" "net/url" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/service/<service>" smithyendpoints "github.com/aws/smithy-go/endpoints" "github.com/aws/smithy-go/middleware" smithyhttp "github.com/aws/smithy-go/transport/http" ) // disableEndpointPrefix applies the flag that will prevent any // operation-specific host prefix from being applied type disableEndpointPrefix struct{} func (disableEndpointPrefix) ID() string { return "disableEndpointPrefix" } func (disableEndpointPrefix) HandleInitialize( ctx context.Context, in middleware.InitializeInput, next middleware.InitializeHandler, ) (middleware.InitializeOutput, middleware.Metadata, error) { ctx = smithyhttp.SetHostnameImmutable(ctx, true) return next.HandleInitialize(ctx, in) } func addDisableEndpointPrefix(o *<service>.Options) { o.APIOptions = append(o.APIOptions, (func(stack *middleware.Stack) error { return stack.Initialize.Add(disableEndpointPrefix{}, middleware.After) })) } type staticResolver struct{} func (staticResolver) ResolveEndpoint(ctx context.Context, params <service>.EndpointParameters) ( smithyendpoints.Endpoint, error, ) { u, err := url.Parse("https://custom.endpoint.api/") if err != nil { return smithyendpoints.Endpoint{}, err } return smithyendpoints.Endpoint{URI: *u}, nil } func main() { cfg, err := config.LoadDefaultConfig(context.Background()) if err != nil { panic(err) } svc := <service>.NewFromConfig(cfg, func(o *<service>.Options) { o.EndpointResolverV2 = staticResolver{} }) _, err = svc.<Operation>(context.Background(), &<service>.<OperationInput>{ /* ... */ }, addDisableEndpointPrefix) if err != nil { panic(err) } }