loading...

My experience using AWS S3 and Multer to upload a photo

jolouie7 profile image Joseph Louie ・3 min read

This is a single file upload only

While creating my Medium clone called Freemium, I decided I want to have a photo upload feature because I've never implemented that feature before. I specifically wanted to use AWS because that's what most companies want here in the bay area. I knew that I wanted to use S3 because that was AWS's file storage system.

What I wanted to happen

I first went on Youtube and looked at a couple of videos on what it might look like uploading photos from my node.js backend to S3. There were many videos of people using node.js to upload to S3 and there were many videos of people using react to upload to S3, but it was kind of hard to find anything that used react -> node.js -> S3. After implementing node.js -> S3 I tried to create a simple react.js frontend to hit my backend but nothing worked. It could have been because I was using redux action creators to hit my backend but I'm not sure.

How did I go about learning AWS S3?

There were 2 articles that stood out to me that I've tried and were up to date.

  • Here is an article by Fabiano. He has revised his article with typescript in mind.
  • File Upload — Express, MongoDB, Multer & S3 by Tyler Knapp. This article was the one I used and worked for me. He also has a post for a react frontend but it's pretty simple. You can find that at the bottom of this article. The only concern I have with his way is that he uses Multer S3 which by the looks of it, hasn't had any commits in 2 years. That's a long time. > In his post he has standard CORS settings but it doesn't work now, maybe because amazon updated their input requirement. They want your CORS to be JSON. Here's what I used:
[
    {
        "AllowedHeaders": [
            "*"
        ],
        "AllowedMethods": [
            "GET",
            "PUT",
            "POST",
            "HEAD"
        ],
        "AllowedOrigins": [
            "*"
        ],
        "ExposeHeaders": [],
        "MaxAgeSeconds": 3000
    }
]
Enter fullscreen mode Exit fullscreen mode

Heres the Bucket Policy that worked for me

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicRead",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::<YOUR BUCKET NAME>/*"
        }
    ]
}
Enter fullscreen mode Exit fullscreen mode

I have my Block public access turned off. You can enable it but I think you might have to configure and look for how to deal with signed URLs.

An issue I ran into when I went to test the photo upload on a live site.

When I manually tested the file upload feature it didn't work. This is the error I got:
"The request signature we calculated does not match the signature you provided. Check your key and signing method."

  • After an hour of googling I figured that it was either:
  1. There was an extra character I didn't expect in my key
  2. I had to include a request header that I was missing
  3. I wasn't allowing my frontend access to my backend aka. CORS
  4. I just needed new keys

I tested every one of the problems in that order and after seeing a GitHub forum post of a comment with 20+ thumbs up saying "I just generated new keys", I tried it and it worked. I didn't believe this would work because my keys were only a week old. My new keys were longer than my old keys though.

Sidenote: other resources I used worked for node.js -> AWS S3, maybe if I didn't use a redux action to try to hit my backend then maybe it might have worked. I can link the resources I think might have worked in the post if anyone wants to know.

Thank You for reading! Comment down below what resources worked for you.

Check out my Medium Clone. Link Here to view Freemium

Discussion

pic
Editor guide