Search code examples
node.jsmongodbamazon-s3aws-sdkmulter

Unable to get the public link to s3 bucket object after uploading from node.js


I was trying to upload an image from node.js server to s3 bucket with the help of multer and @aws-sdk/client-s3. I'm using aws-sdk for javascript v3. When i use aws-sdk for javacript v2, I'm able to get the link to uploaded image using Location attribute. But when using v3, Location attribute is not present in the result object i get.

[
  {
    '$metadata': {
      httpStatusCode: 200,
      requestId: 'REQUEST ID',
      extendedRequestId: 'ID HERE',
      cfId: undefined,
      attempts: 1,
      totalRetryDelay: 0
    },
    ETag: '"EFTAG HERE"',
    ServerSideEncryption: 'AES256'
  }
]

Is there any functions or any other method to get the link to uploaded image?

My purpose is to store image in s3 bucket and save its link to mongoDB database.

Here's the code I'm using for uploading the image to s3 bucket. files contains the array of images from multer. Whenever each image is uploaded using putObjectCommand, i want to return its url also.

const { S3Client, PutObjectCommand } = require("@aws-sdk/client-s3")
const uuid = require("uuid").v1;;

exports.s3Uploadv3 = async (files) => {
    const s3client = new S3Client();
  
    const params = files.map((file) => {
      return {
        Bucket: process.env.AWS_BUCKET_NAME,
        Key: `uploads/${uuid()}-${file.originalname}`,
        Body: file.buffer,
      };
    });
  
    return await Promise.all(
      params.map((param) => s3client.send(new PutObjectCommand(param)))
    );
  };

Solution

  • You are correct that Location key is exposed in aws-sdk (v2), but not in @aws-sdk/client-s3.

    Unfortunately, there is no way to solve it by just using @aws-sdk/client-s3.

    You can solve this by using @aws-sdk/lib-storage along with @aws-sdk/client-s3.

    This exposes the Location key, which is the public url of your file in S3.

    const { S3Client } = require("@aws-sdk/client-s3");
    const { Upload } = require("@aws-sdk/lib-storage");
    const uuid = require("uuid").v1;
    
    exports.s3Uploadv3 = async (files) => {
        return await Promise.all(
            files.map((file) => {
                const client = new Upload({
                    client: new S3Client({}),
                    params: {
                        Bucket: process.env.AWS_BUCKET_NAME,
                        Key: `uploads/${uuid()}-${file.originalname}`,
                        Body: file.buffer,
                    },
                });
    
                return client.done()
            })
        )
    }
    

    client is how you normally create your S3Client object. If you need to pass any extra arguments to the constructor, you can pass that.