0

I'm using MEAN stack to build a chatapp and the user needs to upload a profile image at some point so i decided to use s3 to store the images and get the image URLs stores in my mongodb database so they are displayed in the fronted from the database. I I'm able to successfully upload and image to the bucket and see it in my dashboard but it doesn't update in my database, so when debugging I found out the response from the s3.send(command) doesn't have the location property, so I'm wondering how i could get the uploaded image url. Please help me !!

Here's the part of my code that handles the image upload:

exports.uploadProfileImage = async (req, res) => {
  try {
    const userId = req.params.userId;

    // Use multer upload middleware to handle file upload
    upload.single('image')(req, res, async (err) => {
      if (err) {
        // Handle multer file upload error
        console.log(err);
        return res.status(500).json({ error: 'Multer : Failed to upload profile image' });
      }

      // Check if file exists in the request
      if (!req.file) {
        return res.status(400).json({ error: 'No file found' });
      }

      const file = req.file;

      const buffer = await sharp(file.buffer).resize({height: 300, width: 300, fit: "contain"}).toBuffer()

      // Upload the file to S3
      const command = new PutObjectCommand({
        Bucket: process.env.S3_BUCKET_NAME,
        Key: `${userId}-profile-image.jpg`,
        Body: buffer,
        ContentType: file.mimetype,
      });
      const data = await s3.send(command)
      console.log(data)
      
      // Update the user's profile image URL in the database
      const user = await User.findByIdAndUpdate(
        userId,
        { profileImage: data.Location },
        { new: true }
        );

      res.status(200).json({ user });
    });
  } catch (err) {
    console.log(err);
    res.status(500).json({ error: 'Failed to upload profile image' });
  }
};

When i try to console.log(data.location) i get undefined, and when I log console.log(data) i get this:

{
  '$metadata': {
    httpStatusCode: 200,
    requestId: '20CW7DGKDN5CH2KX',
    extendedRequestId: 'hwnVMq2To+JzIKufMt3t3lOjGfwQz3Ltkb9uU1Tc/nWyU4KbdKS61TM9Hicyyy5FTGM0SzFc4ys=',
    cfId: undefined,
    attempts: 1,
    totalRetryDelay: 0
  },
  ETag: '"2af8d9fd67798fe823c88b06b057b766"',
  ServerSideEncryption: 'AES256'
}

Please can anyone help me solve this ?

1 Answers1

0

The response object (data in your case) from the S3 PutObjectCommand doesn't directly provide the location (URL) of the uploaded object. Instead, you can construct the URL using the known S3 bucket URL format.

The standard format for S3 object URLs is:

https://[BUCKET_NAME].s3.[REGION].amazonaws.com/[OBJECT_KEY]

Given your provided code, you can generate the S3 object URL as:

const s3ObjectURL = `https://${process.env.S3_BUCKET_NAME}.s3.[REGION].amazonaws.com/${userId}-profile-image.jpg`;

Replace [REGION] with the region where your bucket is located. If you're using the default us-east-1 region, the region can be omitted from the URL.

Now, update the user's profile image URL in the database using this constructed URL:

const user = await User.findByIdAndUpdate(
  userId,
  { profileImage: s3ObjectURL },
  { new: true }
);

Note: This method assumes you have public read permissions set on your S3 objects. If not, the generated URL might not be directly accessible without signed URLs or adjusting the object's permissions.

Piyush Patil
  • 14,512
  • 6
  • 35
  • 54