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.
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.
Yeah you guessed it right, the data you store in a bucket.
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:
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.
Till then, keep coding.