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
...
Coding
Setup
Let's create a nextjs app quickly:
npx create-next-app@latest --typescript
Next, add a bucket on AWS S3:
I call olala-bucket
.
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.
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.
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:
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:
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:
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.
Top comments (0)