-
Notifications
You must be signed in to change notification settings - Fork 578
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How Can We Update S3 Client after It Was Created? (Add Region to It) #5081
Comments
Hi @shirady , While S3 operates on a global namespace, meaning that bucket names are unique across AWS regardless of region, the buckets themselves are created in specific regions. When you interact with the S3 API, you're required to make a request to an S3 regional endpoint, and these endpoints are region-based.
As a best practice, it's recommended to configure your client with both credentials and the region ahead of time. This ensures predictability when your application makes API calls. So for example, if you are running the SDK code in a container, the container needs to inject the correct region and credentials ahead of the client creation, same goes for an EKS pod, or an AWS Lambda. Regarding updating the region of an existing client: const client = new S3Client({});
client.config.region = "us-east-1"; This is how to update the region post-instantiation. However, this approach is not recommended as it can lead to potential problems, especially if the client is shared across different parts of the application.
Creating a new client is not recommended. Unless your application makes requests to different regions ie: const clientForUSEast1 = new S3Client({ region: "us-east-1" });
const clientForEUWest2 = new S3Client({ region: "eu-west-2" }); I want to emphasize, you should be creating your client once, in the global scope of your application, when you have the region and credentials. Avoid updating it after creation. As far as breaking changes go, I personally don't think a change from: @trivikr created a codemod which is a tool that takes v2 code and converts it to v3. Please note this tool is in early stages of development and is not perfect. Let me know if there's anything I can help with. |
Hi @RanVaknin , I would like to respond in different subjects so I numbered it (hoping it is easier to track).
I'm planning to use this
|
Hi @shirady ,
The power of the SDK client is that you almost never need to configure the Typically, there is no need to supply an
Most of the current members of the JS SDK team have started working on this team after v3 launched. While flip-flopping between the two versions is easy for us, it can prove challenging for developers who worked with v2 for years and are only making the change now. We are slowly learning about the challenges of migrating as more people move to v3. I have already added some backlog items for us to add to the migrating guide. If you have anything in mind that was missing please let me know so I can discuss it with the team. Thanks again, |
Hi @RanVaknin ,
'use strict';
const { S3 } = require('@aws-sdk/client-s3');
const https = require('https');
const { NodeHttpHandler } = require('@aws-sdk/node-http-handler');
async function main() {
const s3_client_params = {
endpoint: 'https://s3.amazonaws.com',
region: 'us-west-2',
credentials: {
accessKeyId: process.env.ACK,
secretAccessKey: process.env.SACK,
},
forcePathStyle: true,
signatureVersion: 'v4',
requestHandler: new NodeHttpHandler({
httpsAgent: new https.Agent({
keepAlive: true,
rejectUnauthorized: false,
})
}),
};
try {
const s3 = new S3(s3_client_params);
const res = await s3.listBuckets({});
console.log(res);
console.log('SUCCESS check_list_buckets');
} catch (err) {
console.error('FAIL check_list_buckets got error', err);
}
}
main(); I'm aware that it searches for the region in different places (here), but mentioning it explicitly in the s3 client is first in precedence (in my aws config
In the code we set the endpoint, we have cases where the endpoint is not AWS, but I think that in AWS cases I will remove it, thank you. In cases where the endpoint is not AWS, why are we still required to add the region?
Where can I see it? I can have a look at it and add suggestions related to s3. |
Hi @shirady , You are seeing this error because when using the global S3 endpoint While regional endpoints align with the specified region in the SDK and won't cause a mismatch, the global endpoint specifically anticipates the 'us-east-1' signature. Thus, specifying a region like I have already checked the S3 docs and this is not mentioned explicitly, but can be inferred from the the error:
I converted this code to v2 and can see that in v2 the requests fails the same way, but the SDK v2 redirects after failure. My guess is that it uses the returned 'use strict';
const AWS = require('aws-sdk');
const https = require('https');
AWS.config.update({
endpoint: 'https://s3.amazonaws.com',
region: 'us-west-2',
s3ForcePathStyle: true,
signatureVersion: 'v4',
httpOptions: {
agent: new https.Agent({
keepAlive: true,
rejectUnauthorized: false,
})
}
});
const s3 = new AWS.S3();
var request = s3.listBuckets();
request.on('httpData', function(statusCode, headers) {
console.log('----- HEADERS -----');
console.log('Status Code:', statusCode);
for (var header in headers) {
console.log(header, ':', headers[header]);
}
});
request.on('httpData', function(chunk) {
console.log('----- DATA CHUNK -----');
console.log(chunk.toString());
});
request.send(); Will result in an initial failure (400 error) followed by a redirect to the expected region us-east-1
I don't know why the v2 SDK does this redirect implicitly, but my guess is this was a customization written after feature request. In v3 we ̶o̶n̶l̶y̶ ̶r̶e̶d̶i̶r̶e̶c̶t̶ ̶o̶n̶ ̶3̶0̶1̶ ̶e̶r̶r̶o̶r̶s̶ ̶(̶r̶e̶d̶i̶r̶e̶c̶t̶s̶)̶ ̶a̶n̶d̶ ̶n̶o̶t̶ ̶4̶0̶0̶ do not follow redirects. So now that we know why there's a change in behavior, we can address it.
Regarding refactoring your code and documentation. It has come to our attention only recently that this is a wide spread issue of initializing the client in a function scope and Im personally working on documentation to address this. So you are not wrong to assume that the current structure is correct, because there is no official documentation that says otherwise. This is how I would re-write your code: 'use strict';
const { S3 } = require('@aws-sdk/client-s3');
const https = require('https');
const { NodeHttpHandler } = require('@aws-sdk/node-http-handler');
const s3_client_params = {
// endpoint: 'https://s3.amazonaws.com', remove this as per suggestions from last section
region: 'us-west-2',
credentials: {
accessKeyId: process.env.ACK,
secretAccessKey: process.env.SACK,
},
forcePathStyle: true,
// signatureVersion: 'v4', you can remove this as JS SDK v3 uses sigv4 as a standard.
requestHandler: new NodeHttpHandler({
httpsAgent: new https.Agent({
keepAlive: true,
rejectUnauthorized: false,
})
}),
};
const s3 = new S3(s3_client_params);
async function listBucketsForAccount() {
try {
const res = await s3.listBuckets({});
console.log(res);
console.log('SUCCESS check_list_buckets');
} catch (err) {
console.error('FAIL check_list_buckets got error', err);
}
}
listBucketsForAccount(); You can find more specific upgrade in UPGRADING.md I hope this clarifies things. |
Hi Ran, Regarding the suggested options -
I understand the best option is supplying the region without using the endpoint, but I still want to understand the second option. As said before, we create the s3 client once for specific credentials and we should set the region to the bucket that we use (if we use 2 buckets in different regions we should create 2 clients). If I'll use the global aws endpoint (https://s3.amazonaws.com) and the region 'us-east-1' listBuckets would work, but in the next action I'll have that involves a bucket as a required parameter it would fail (for example headObject, ListObjects, etc.). Hence I am not sure it is a valid option (solves only a client that operates listBuckets).
I still didn't understand why do need to set the region for endpoints that are not aws, if you can explain it, please. Another question - I looked at the link of UPGRADING.md again since you attached it and saw that the library of - const { NodeHttpHandler } = require('@aws-sdk/node-http-handler');
+ const { NodeHttpHandler } = require('@smithy/node-http-handler'); How do you communicate such changes? I was not aware of it until now. |
Hi @shirady,
I dont see a real world scenario where the same JS file will call a mock s3 endpoint and also the actual s3 service.
This is because listBuckets is designed to be a global operation - listing all the buckets in all regions (with the signature caveat that has to be specified in us-east-1) the issue you linked about the global s3 client is aimed to solve those redirects for you and is currently being worked on. But as I mentioned relying on the global endpoint is not recommended. The recommended solution is to let the SDK resolve the endpoint for you using the regional endpoints. You should move to regional endpoint because:
When you go to upgrade your dependencies you'll get an explicit warning telling you you need to upgrade. For the time being this is just a warning and we have internal re-exports making this transparent, but in the future this will be changed into an error and an explicit change will be required: $ npm i @aws-sdk/node-http-handler
npm WARN deprecated @aws-sdk/node-http-handler@3.374.0: This package has moved to @smithy/node-http-handler You can learn more about this change here Thanks again, |
Hi @RanVaknin,
I have real endpoints that are s3-compatible (not a testing mock) and I use the same code to create s3 clients for them and AWS. Anyway, in case I don't send a region I have the error of
Using Thank you! |
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs and link to relevant comments in this thread. |
Describe the issue
Hello,
1) Client Region And Update Client
From reading other issues (some examples: #1802, #1807, #1845, #3469) I know that in the AWS SDK V3, we need to pass the region of the bucket the client will work on.
I thought about wrapping the commands with a "guess" of the region and then handling the error and taking the region from it (for example, when using
listObjects
with another region we getAuthorizationHeaderMalformed
and have the region in the error).But I don't see we have
s3.config.update
(s3 is the variable that holds the instance of S3). I know that we don't have the global update, but I'm looking for updating a specific instance.I would add, that at this point in the code, I don't have the parameters that created this s3 so I just want to update it with the right region.
I don't mind creating a new one - but I need to find a way to extract the map of params from the existing client.
What do you suggest as a solution?
2) Detailed Breaking Changes
BTW, except for the upgrading notes, is there more detailed documentation about breaking changes between the 2 versions? (aws sdk v2 and aws sdk v3) because I keep finding out about changes in the trial-error process... for example, there is no mention in the notes about changes in the commands that we use to perform the actions.
Thank you!
Links
https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/s3/
https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/Package/-aws-sdk-client-s3/Class/S3/
https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/Package/-smithy-smithy-client/Class/Client/
https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/introduction/#getting-started
The text was updated successfully, but these errors were encountered: