Uploading Image to Amazon S3 with NestJS
So you are writing your side project or your next big startup product with the NestJS framework đ, and then you reach a point where you want to upload files, images to be specific, to Amazon Simple Storage Service(S3), but you just canât figure it out⌠this article is just for you.
But before we begin, letâs talk a little on the S3. Amazon S3 is an object storage service that can be used to store and protect any amount of data for a range of use cases, such as data lakes, websites, mobile applications, backup and restore, archive, enterprise applications, IoT devices, and big data analytics. In summary, you can store almost any type of data with Amazon S3. There are a lot of things to learn when working with S3, but for the nature of this article, we are limited to these few.
Bucket
Just as a real bucket is used to contain any form of matter, an Amazon S3 bucket is used to contain any type of data, known as objects.
Object
Yeah you guessed it right, the data you store in a bucket.
Key
This is the key used to identify an object in an S3 bucket. So when you upload an image to S3, you get a URL similar to â https://<bucket-name>.s3.amazonaws.com/<object-key> â. âobject-keyâ here can be the name of the object you uploaded to an S3 bucket.
Now youâve gotten the basic idea of S3, letâs upload. First of all, make sure you have an AWS account. I will be illustrating with the food_demo repo, of which I created for my previous article. To have access to your AWS resources, it is recommended that you create an IAM user, which gives permission to access your cloud resources without using your Root user account credentials. We can do this with the following steps.
- Sign in to your AWS account as the Root user, with the link: https://console.aws.amazon.com/iam
- After that, you should see a navigation panel similar to this:
- Click on the âUsersâ option, and click âAdd usersâ:
- Youâll be taken to a page similar to this:
Use your desired username, and choose the âAccess key-Programmatic accessâ option for credential type. This helps you access your S3 service from your code. Then click the Next button.
You should be taken to a page similar to this:
- Select the âAmazonS3FullAccessâ checkbox. This gives the IAM user full access to S3 service. After this, an AccessKeyID and a secret access key are generated. They will be used in your API source code with AWS SDK to access your S3 service. Then you can just keep clicking âNextâ till you click the âCreate Userâ button. You will get to see a page similar to:
Youâve successfully created an IAM user with Access Key ID and Secret Access key. You can copy and paste those key values in your .env file, with variable names FOOD_DEMO_S3_ACCESS_KEY_ID and FOOD_DEMO_S3_SECRET_ACCESS_KEY respectively, because you will be using them soon. Click the âCloseâ button and you should still see your IAM user.
Next, you have to create an S3 bucket to store your files for your API. On your search bar, just type âS3â and you should see the service come up. Click it, and you should see your Amazon S3 Dashboard.
- Click on âCreate bucketâ button:
- Fill in your desired bucket name, mine is âfood-demoâ. Choose your AWS region.
- To have access to your bucket from your API, you will want to un-select the âBlock all public accessâ checkboxes:
Then you can leave everything else as it is, and âCreate bucketâ. You should see your newly created bucket.
So, 3 variables you need in your .env file are:
- FOOD_DEMO_S3_ACCESS_KEY_ID=<IAM user Access key ID>
- FOOD_DEMO_S3_SECRET_ACCESS_KEY=<IAM user Secret Access Key>
- FOOD_DEMO_S3_BUCKET=<food-demoâŚor whatever name you chose>
Over to your next big application⌠but, you will have to install some important packages:
npm install aws-sdk
npm install -D @types/multer
aws-sdk helps you manipulate AWS services from your code.
@types/multer helps you work with files in typescript and multer.
If you are building with docker-compose, donât forget to build:
docker-compose build
Next, you have to configure your code to use your IAM credentials, else AWS wonât know who is making the request to your S3 service.
- Open your main.ts file, and add the following:
Before you start uploading your files to S3, you must know that there are parameters required for S3 upload operation:
- Bucket â your created S3 bucket, in this case, food-demo.
- Key â your object key. This can be the name of the file you want to upload.
- Buffer â this is simply the file data.
Coming to my food demo data entity, hereâs what I have:
The image column will contain the URL of the image after it has been uploaded to your S3 bucket.
Coming to my food-demo service:
From the above written code, you can see that S3 is imported from the AWS-SDK and instantiated in the uploadImageToS3 method. This method is called in the createMenuItem method, in order to get the image URL and assign it to the image key of the food object.
Coming to the food controller.ts file:
When observing â return this.foodMenuService.createMenuItem(body.name, body.price, file.originalname, file.buffer) â with â createMenuItem (name: string, price: number, imageName: string, body: Buffer) â , you can see that both file.originalname and imageName represent the parameter, âKeyâ, while file.buffer and body represent the parameter, âBodyâ, as weâve already provided our âBucketâ parameter in uploadImageToS3 method.
Testing the API in my favourite client, Insomnia đ:
And there you have it.
I hope this was pretty straightforward and helpful. Please feel free to reach out to me on LinkedIn or Twitter. See you next time.
Till then, keep coding.