DEV Community

Mohit Kumar Yadav
Mohit Kumar Yadav

Posted on • Edited on

Upload files to S3 buckets from react

Disclaimer - When uploading files to s3 directly from front end, your AWS credentials are exposed in the network tab. Refrain from uploading files to protected S3 buckets directly from FE. Always use a server to upload files.

You need to install aws-sdk npm package in order to upload files to s3 buckets.

npm install aws-sdk --save

Make sure the bucket has following policy

<?xml version="1.0" encoding="UTF-8"?>
 <CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <CORSRule>
        <AllowedOrigin>*</AllowedOrigin>
        <AllowedMethod>POST</AllowedMethod>
        <AllowedMethod>GET</AllowedMethod>
        <AllowedMethod>PUT</AllowedMethod>
        <AllowedMethod>DELETE</AllowedMethod>
        <AllowedMethod>HEAD</AllowedMethod>
        <ExposeHeader>ETag</ExposeHeader>
        <AllowedHeader>*</AllowedHeader>
    </CORSRule>
</CORSConfiguration>
Enter fullscreen mode Exit fullscreen mode

The ETag header must be exposed or bigger uploads will not complete.


Let's write some React
import AWS from 'aws-sdk'

in the component constructor set the AWS access key and the secret keys. You get them straight from the aws console.

AWS.config.update({
  accessKeyId: AWSAccessKeyId,
  secretAccessKey: AWSSecretKey
})
Enter fullscreen mode Exit fullscreen mode

Create the bucket in the constructor as well
Always double check bucket's name and region.

this.myBucket = new AWS.S3({
  params: { Bucket: 'video-bucket-xyz'},
  region: 'ap-south-1',
})
Enter fullscreen mode Exit fullscreen mode

Now when ever you want to upload a file to the bucket call the following function and pass the selected file as function argument.

uploadFile = (file) => {
  const params = {
    ACL: 'public-read',
    Key: file.name,
    ContentType: file.type,
    Body: file,
  }
  this.myBucket.putObject(params)
    .on('httpUploadProgress', (evt) => {
      // that's how you can keep track of your upload progress
      this.setState({
        progress: Math.round((evt.loaded / evt.total) * 100),
      })
    })
    .send((err) => {
       if (err) {
         // handle the error here
       }
    })
}
Enter fullscreen mode Exit fullscreen mode

you can read more about putObject here.


References
aws-sdk

Top comments (14)

Collapse
 
ashermiti profile image
Asher Mitilinakis

This is so helpful thank you! One question I have is if you wanted to ensure that the files go into a sub-folder within your bucket, do you know how best to go about this? I've tried entering some further params into the myBucket variable but have been unsuccessful.

Many thanks!

Collapse
 
setoryz profile image
Odukoya Jesuseyitan

When you want the files to go to a subfolder, You should add the location before the file name in the key and separate each sub-folder by a forward slash '/'.

For example: if I want to save to the 'profiles' folder inside 'images' in my bucket,
My key is going to be: images/profiles/file.name

const params = {
    ACL: 'public-read',
    Key: `images/profiles/${file.name}`,
    ContentType: file.type,
    Body: file,
  }
Enter fullscreen mode Exit fullscreen mode

And yeah do this on the backend to avoid exposing your keys.

Collapse
 
ashermiti profile image
Asher Mitilinakis

Amazing, I managed to figure this out in the end. Thanks for your help too! :)

Collapse
 
saltaformajo profile image
Saltaformajo

Your secret key is publicly available, isn't it?

Collapse
 
amolo profile image
Amolo

Is it really a good practice to leave the Access and Secret Keys public on the front-end?

Collapse
 
mohitkyadav profile image
Mohit Kumar Yadav • Edited

I think it's not a good practice.

Collapse
 
amolo profile image
Amolo

Then you should probably put a disclaimer at the beginning.

Thread Thread
 
mohitkyadav profile image
Mohit Kumar Yadav

ohh, yeah sorry, I forgot. Thank you for pointing out 😊.

Collapse
 
syeutyu profile image
Dayzen

I agree with you

Collapse
 
abarajithan profile image
Abarajithan

To upload large files (1-10GB) from react into s3, can we automatically break the file into pieces, send and reassemble into one file? With same API?

Collapse
 
mohitkyadav profile image
Mohit Kumar Yadav

hey, when you do putObject it already breaks the file into pieces, you need not to worry.

Collapse
 
andrewbaisden profile image
Andrew Baisden

You also forgot to add syntax highlighting to your code blocks many people miss that on here 😄

Collapse
 
mohitkyadav profile image
Mohit Kumar Yadav

Hey thank you, didn't know about that 😊.

Collapse
 
ayomiku222 profile image
Ayomiku Olatunji John

Please how can i get the url of the uploaded file?