aws-sdk-go-v2 icon indicating copy to clipboard operation
aws-sdk-go-v2 copied to clipboard

Add way to get the region of an API client.

Open oakad opened this issue 5 years ago • 4 comments

Application manipulating APIs in multiple regions often need to adjust their behavior depending on whether different assets are located in the same or different regions.

To this end, it was handy to obtain the configured region directly from various service clients. Unfortunately, new client API hides region information in the private options object and provides no access to it.

Kindly return the region getter to the client object.

oakad avatar Nov 02 '20 15:11 oakad

Thanks for reaching out this this issue @oakad. Currently the API client's don't provide a way to extract some or all of the options that the client was created with. One way to address this would be to add a GetAPIClientOptions (or similarly unique named method that won't clash with API operations) to the client. This method would call Copy on the client's option and eturn that copy.

func (c *Client) GetAPIClientOptions() Options {
     return c.options.Copy()
}

jasdel avatar Nov 12 '20 00:11 jasdel

Not all options are equally useful (in the sense, that at some point we can simply tug the config along with the client). But region is of importance - we have dozens of region checks in our aws apps.

oakad avatar Nov 13 '20 03:11 oakad

We have noticed this issue has not received attention in 1 year. We will close this issue for now. If you think this is in error, please feel free to comment and reopen the issue.

github-actions[bot] avatar Mar 04 '22 00:03 github-actions[bot]

I still believe region and actual API endpoint targeted should be exposed in the client interface. For example, gRPC client offers "Target()" method, so it's possible to check where is it connected to at any time.

oakad avatar Mar 04 '22 02:03 oakad

so it's possible to check where is it connected to at any time.

Note this isn't possible for many services as the endpoint is dynamic based on the operation input (e.g. s3 bucket names are hoisted to the URL hostname when virtual host addressing is enabled).

aajtodd avatar Feb 21 '23 14:02 aajtodd

And yet, regions are critically important when dealing with S3. My s3 code is choke full of bucket region code queries. :-)

oakad avatar Feb 22 '23 03:02 oakad

Increasing the prio on this in the interest of parity with v1, where such a thing is possible:

fmt.Println(*svc.Config.Region) // service clients embed client.Client, which has aws.Config

I'm not inclined to "guard" access to Options in any way, though:

  1. I don't see a compelling reason to do so. Go as a language doesn't put a lot of emphasis on "guard rails" or object access control outside of the ability to choose whether to export a field. When usage/access semantics matter, it's indicated via documentation.
  2. The method space on Client is currently "pure" in the sense that we only generate modeled operations as methods. The alternative of keeping Options unexported and exposing something like func (*Client) Options() breaks that purity and adopting exposure of methods like that as a paradigm puts us in a position to hit naming collisions in the future (as unlikely as that might be).

To wit I think the following is all we need here:

  // Client provides the API client to make operations call for Amazon Simple
  // Storage Service.
+ //
+ // DO NOT instantiate a client directly - see [New] and [NewFromConfig].
  type Client struct {
-     options Options
+     // API client options.
+     //
+     // DO NOT modify client options directly - either use functional options
+     // on a per-operation basis, or instantiate a separate client.
+     Options Options
  }

lucix-aws avatar Sep 24 '23 16:09 lucix-aws

At this point of time, the right thing may be to add the region to each and every request, autopopulated from config. Long gone are the days when everything was stuck in "us-east-1". :-)

oakad avatar Sep 25 '23 01:09 oakad

Are you asking for the ability to override region per-request? That's possible today, on every service operation.

svc.ListBuckets(context.Background(), nil, func (o *s3.Options) {
    o.Region = "wherever"
})

lucix-aws avatar Sep 25 '23 14:09 lucix-aws

Does this mean I can have a single client for all the regions and the client config region will only be used for defaults? No performance penalty, no hidden catches?

oakad avatar Sep 25 '23 14:09 oakad

Does this mean I can have a single client for all the regions and the client config region will only be used for defaults?

Yes.

No performance penalty, no hidden catches?

None. Per-operation overrides will actually be more economical than multiple clients since canonically "expensive" resources will be shared. As of this writing that will mostly apply to the HTTP client, assuming we're defaulting it for you:

// assuming cfg.HTTPClient is not set, each of these clients gets their own default HTTP client
// each with their own instance of http.Transport
svcI := s3.NewFromConfig(cfg, func (o *s3.Options) {
    o.Region = "us-east-1"
})
svcJ := s3.NewFromConfig(cfg, func (o *s3.Options) {
    o.Region = "us-east-2"
})

The above example at scale requires n transports to be created for n regions.

regions := loadEveryAWSRegion() // []string
svcK := s3.NewFromConfig(cfg, func (o *s3.Options) {
    o.Region = "us-east-1"
})

for _, region := range regions {
    svcK.DoSomething(ctx, ..., func (o *s3.Options) {
        o.Region = region
    })
}

The above is 1 transport for n regions.

Notice that the func(*Options) input is variadic, you can build up your own logic around this as makes sense for your application, if for example you want to change other parts of the config on a per-operation basis.

Note that if you're using the timestream service(s) you'll run into #2163 if you try to change the region.

[EDIT: code typo]

lucix-aws avatar Sep 25 '23 14:09 lucix-aws

I'd say, this stuff should be added to the docs near the beginning (in some sort of best practices section). After all these years I suddenly learn that we don't have to maintain a bunch of client objects. :-)

oakad avatar Sep 25 '23 15:09 oakad

⚠️COMMENT VISIBILITY WARNING⚠️

Comments on closed issues are hard for our team to see. If you need more assistance, please either tag a team member or open a new issue that references this one. If you wish to keep having a conversation with other community members under this issue feel free to do so.

github-actions[bot] avatar Nov 29 '23 17:11 github-actions[bot]