Push that to AWS S3 for me
Tags: aws, javascript, react, nextjs
Published: 2021-10-16 03:04:43

---
canonical_url: "https://www.thangphan.xyz/posts/push-that-to-aws-s3-for-me/"
---
Hi friend! Today, I'm going to introduce to you how I upload the image to AWS S3 using Javascript.

Let's dig in!

### Core Concept

Grap a drink and take a glance with about the core concept of AWS S3. I'm try to keep it simple as much as possible.

Here we go:

#### Bucket

Bucket is where contains the objects we would like to upload, and it is unique global.

#### Object

The object might be an image, a font file, or whatever file we want to upload to Bucket. The object has a unique key, and metadata like the type of image, type of file.

#### CORS

By default, AWS S3 will block public access, and our object will be private. So we need to set up cors for our object in order to public it.

### Flow

My goal is to allow the user can upload the object to the bucket that I defined.In AWS S3, we can use presigned URL, in order to allow users to do this..

First, We use the bucket's name, AWS access key, AWS secret key to get the signed URL. Second, we use the signed URL to allow users to make the request to our bucket like: `putObject`, `deleteObject`...

Here is the flow: ![My Flow](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/meqa4qt8jjtohrghmrqr.png)

### Coding

#### Setup

Let's create a nextjs app quickly:

```tsx
npx create-next-app@latest --typescript
```

Next, add a bucket on AWS S3:

I call `olala-bucket`.

![My bucket](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1xep61neegd4jip988cd.png)

You need to create an AWS access key and AWS secret key.

#### Write code

I install `aws-sdk` to make a connect to AWS s3.

First of all, I need to create an API nextjs that creates the signed URL. It receives the key of the object, fileType from the user's request.

```tsx
import type {NextApiRequest, NextApiResponse} from 'next'
import {responseError} from '@/utils/api-stuff'
import aws from 'aws-sdk'

// you need to set up these values in .env file

const s3 = new aws.S3({
  accessKeyId: process.env.AWS_ACCESS_KEY,
  secretAccessKey: process.env.AWS_SECRET_KEY,
})

function responseError(res: NextApiResponse, message: string) {
  return res.status(404).json({message})
}

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse,
) {
  const {key, fileType} = req.query

  if (!key) {
    return responseError(res, 'Key of object is required!')
  }

  if (!fileType) {
    return responseError(res, 'MetaData of object is required!')
  }

  const bucketParams = {
    Bucket: process.env.BUCKET_NAME,
    Key: key,
    ContentType: fileType,
  }

  try {
    const signedUrl = await s3.getSignedUrl('putObject', bucketParams)

    res.status(200).json({url: signedUrl})
  } catch (error) {
    res.status(401).json({message: (error as Error).message})
  }
}
```

Make a request to receive signed url, and save it to a value.

```tsx
const signedUrlRef = React.useRef<string | null>(null)

React.useEffect(() => {
  const query = new URLSearchParams({
    // name of object
    key: 'naruto',
    fileType: 'image/jpeg',
  })

  async function getSignedUrls() {
    try {
      const {url} = await fetcher(`/api/your-bucket?${query}`)
      if (!signedUrlRef.current) {
        signedUrlRef.current = url
      }
    } catch (error) {
      console.log('GetSignedUrls._error:', error)
    }
  }

  getSignedUrls()
}, [])
```

And add a form element to submit our image:

```tsx
async function handleFormSubmit(event: React.FormEvent<HTMLFormElement>) {
  event.preventDefault()
  if (!signedUrlRef.current) return

  const {myFile} = event.currentTarget
  const file = myFile.files[0]

  try {
    await fetch(signedUrlRef.current, {
      method: 'PUT',
      headers: {
        'Content-Type': file.type,
      },
      body: file,
    })
  } catch (error) {
    console.log('pushObjectToBucket._error:', error)
  }
}
return (
  <div>
    <form onSubmit={handleFormSubmit}>
      <input type="file" name="myFile" />
      <button>Submit</button>
    </form>
  </div>
)
```

This is all of code:

```tsx
import * as React from 'react'

const fetcher = (args: string) => fetch(args).then((res) => res.json())

function Demo() {
  const signedUrlRef = React.useRef<string | null>(null)

  React.useEffect(() => {
    const query = new URLSearchParams({
      // name of object
      key: 'naruto',
      fileType: 'image/jpeg',
    })

    async function getSignedUrls() {
      try {
        const {url} = await fetcher(`/api/your-bucket?${query}`)
        if (!signedUrlRef.current) {
          signedUrlRef.current = url
        }
      } catch (error) {
        console.log('GetSignedUrls._error:', error)
      }
    }

    getSignedUrls()
  }, [])

  async function handleFormSubmit(event: React.FormEvent<HTMLFormElement>) {
    event.preventDefault()
    if (!signedUrlRef.current) return

    const {myFile} = event.currentTarget
    const file = myFile.files[0]

    try {
      await fetch(signedUrlRef.current, {
        method: 'PUT',
        headers: {
          'Content-Type': file.type,
        },
        body: file,
      })
    } catch (error) {
      console.log('pushObjectToBucket._error:', error)
    }
  }
  return (
    <div>
      <form onSubmit={handleFormSubmit}>
        <input type="file" name="myFile" />
        <button>Submit</button>
      </form>
    </div>
  )
}

export default Demo
```

Let's now hit the submit button and check our bucket:

![Upload file to AWS S3 successfully](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6nubmbr60ur3ycqog7xu.png)

### Conclusion

Here is the way I upload the image to AWS S3 using nextjs framework. Why don't try to upload your image or whatever file you would like to add to the bucket.