14

I'm trying to store a user's uploaded files in S3 using presigned URLs. This works fine, but I'm using UUIDs as the filename to avoid conflicts. I need to be able to save the file's original filename, so I'm passing it as metadata in the signed upload URL:

const url = await s3.getSignedUrlPromise('putObject', { Bucket: UPLOAD_BUCKET, Key: key, Expires: AWS_UPLOAD_EXPIRATION / 1000, ContentType: contentType, Metadata: { filename: originalFilename }, }); 

This also appears to work fine (the metadata is showing in the AWS console). How can I access this metadata? When the client needs to display one of these images, they request a presigned download URL from the server which is generated like this:

const url = await s3.getSignedUrlPromise('getObject', { Bucket: UPLOAD_BUCKET, Key: key, Expires: AWS_DOWNLOAD_EXPIRATION / 1000, }); 

This URL doesn't appear to include the metadata, and the return value of getSignedUrlPromise is a string, so there doesn't seem to be any room for anything other than the URL itself. I assumed there would be an S3 method for fetching just the metadata, but as far as I can tell it doesn't exist (or has an unintuitive name). This is especially confusing considering the getObjectTagging and getObjectLegalHold methods exist. How can I access metadata through a presigned URL? If that's not possible, how can I fetch the metadata using the AWS SDK? If that's not possible, I must be misunderstanding the point of metadata.

1 Answer 1

26

You cannot fetch metadata using URL, but you can use s3.headObject method:

const config = new AWS.Config({ accessKeyId: 'your acessKey', secretAccessKey: 'your secret', region: 'your region', }); const s3 = new AWS.S3(config); const params = { Bucket: 'your bucket', Key: 'your assetKey' } const metaData = await s3.headObject(params).promise(); 

Documentation

Sign up to request clarification or add additional context in comments.

6 Comments

Thanks for the quick response. This will work great. Of course the function for getting an object metadata isn't called getObjectMetadata..
If you're looking for a way to remember this and are familiar with http method names, HEAD is the underlying request method. Hence headObject. see docs.aws.amazon.com/AmazonS3/latest/API/API_HeadObject.html . I do agree with you on the bad naming because they're building an sdk which is supposed hide implementation details. Also, methods should start with verbs.
What if I want to retrieve both the object and its metadata? With the current approach, you need to make two requests: getSignedUrlPromise and headObject, correct? That seems to be rather ineffective when you want to obtain information about the same object - is there a way of performing that in a single request?
I didn't test with the sdk, however a raw GET returns the user metadata via headers e.g. x-amz-meta-{userMetaName}={val}. So only a single request should be necessary.
const {Body, Metadata} = await s3.getObject({Bucket, Key}).promise() gets you both metadata and object @Bianca
For AWS SDK for JavaScript v3, see headObject § S3 | S3 Client and the HeadObjectCommand class.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.