Angular With NodeJS Image Upload To AWS S3 - EASY!!
Tags: angular, aws, node, tutorial
Published: 2019-10-22 05:41:02

Have you always wondered how to upload an image in your Angular app to your S3 Bucket on Amazon?

I'm going to teach you a very easy way to do it using Angular, NodeJS, and AWS S3 without getting in debt in IAM and other security stuff that will make this tutorial even longer. If you want to learn more about that, please do some extra research. Remember, for a real project NEVER use your root credentials.


Requirements:
-Angular CLI Installed
-NodeJS Installed
-Have an AWS Account (Don't worry, you won't be charged for whatever we do in this tutorial)
-Have some basic understanding on AWS, Angular, and NodeJS.

<center><h2>AWS</h2></center>
<img width="120px" src="https://thepracticaldev.s3.amazonaws.com/i/s8bksob4rhjxgpmfnhmz.png" />

1) Go to your AWS Console.
2) On the top right, you will see your account name, click on it then click on <i>My security credentials</i>.
<img width="300px" src="https://thepracticaldev.s3.amazonaws.com/i/uin6e7ez78h3l8tkufxz.png" />
3) A modal will appear, click on "Continue To Security Credentials".
<img width="300px" src="https://thepracticaldev.s3.amazonaws.com/i/zh3yjhxgl8hc8dcf8mx5.png" />
4) Click on <i>Access Keys</i>.
5) Click on <i>Create New Access Key</i>.
<img width="500px" src="https://thepracticaldev.s3.amazonaws.com/i/vs5nlr58iih8ld6dv5gy.png" />
6) Copy/Paste your Keys in a SECURE PLACE.
<img width="500px" src="https://thepracticaldev.s3.amazonaws.com/i/fvrilm8mxaqivrfy77ca.png" />

<center><h2>AWS S3</h2></center>

<img width="100px" src="https://thepracticaldev.s3.amazonaws.com/i/rtfu6xnfnnt0a5mdh3p0.png" />

1) Navigate to the AWS S3 Service.
2) Create a new S3 bucket.
<img width="500px" src="https://thepracticaldev.s3.amazonaws.com/i/52xgztzu5yt5idtyk8uh.png" />
3) Give your bucket a name and click NEXT and then NEXT again.
<img width="500px" src="https://thepracticaldev.s3.amazonaws.com/i/10jzw6hmozxflrnuco08.png" />
4) Uncheck the checkbox as shown in the picture and click NEXT.
<img width="500px" src="https://thepracticaldev.s3.amazonaws.com/i/6h2vcykf45wjfqwo4703.png" />
5) Click on <i>Create Bucket</i>.
<img width="500px" src="https://thepracticaldev.s3.amazonaws.com/i/8mi95spvdt7yj4bzxks3.png" />


<center><h2>Angular App</h2></center>

<img width="100px" src="https://thepracticaldev.s3.amazonaws.com/i/o0vwd8607j64u96hyhwk.png" />

1) Clone the following REPO:
https://github.com/devpato/angular-nodejs-s3-upload

<i>Note: Inside the folder FINAL, you will find the complete code of this project. I have setup the architecture of the super tiny app, so you don't waste time doing so. </i>

2) Go to your <i>app.component.html</i> and paste the following code:

<i>Note: Don't forget change the url of the image source to have your bucket name.</i>
   ```html
   <input (change)="onImagePicked($event)" placeholder="Upload Image" 
   type="file" />
   <button (click)="onImageUpload()">Upload Image</button>

    <div *ngIf="imageUrl">
     Preview Image from AWS
     <br />
     <img width="200px" src="https://YOUR S3 BUCKET 
     NAME.s3.amazonaws.com/{{ 
     imageUrl }}" 
     />
    </div>
   ```
3) Go to your <i>app.component.ts</i> and paste the following line at the top of the file:
   ```javascript
   import { ImageUploadService } from './image-upload.service';
   ```
4) Go to your <i>app.component.ts</i> and paste the following code:
   ```javascript
   imageObj: File;
   imageUrl: string;

   constructor(private imageUploadService: ImageUploadService) {}

   onImagePicked(event: Event): void {
    const FILE = (event.target as HTMLInputElement).files[0];
    this.imageObj = FILE;
   }

   onImageUpload() {
    const imageForm = new FormData();
    imageForm.append('image', this.imageObj);
    this.imageUploadService.imageUpload(imageForm).subscribe(res => {
      this.imageUrl = res['image'];
    });
   }
   ```
5) Go to your <i>image-upload.service.ts</i> and paste the following code:
   ```javascript
   imageUpload(imageForm: FormData) {
    console.log('image uploading');
    return this.http.post('http://localhost:3000/api/v1/upload', 
    imageForm);
   }
   ```

<center><h2>NodeJS Server</h2></center>

<img width="100px" src="https://thepracticaldev.s3.amazonaws.com/i/di1rnhlvdcrhvetuskwp.png" />

1) Go to the folder called BACKEND

<i>Note: in your terminal run the following to install the packages needed for this project.</i>

   ```javascript
   npm i --save multer multer-s3 aws-sdk dotenv nodemon
   ```
-multer and multer-s3 are the packages to handle the picture uploading.
-aws-sdk will give us access to the aws libraries
-dotenv will give us access to the environment variables.

<i>FYI: nodemon package is only used for you so that you do not have to restart the server manually every time you make a change. This package is not need for uploading images to s3.</i>

2) Go to your <i>.env</i> file and enter the KEYS we generated from AWS. 

<i>The keys you put in a safe location.</i>

3) Inside of the <i>service.js</i> paste the following code;
   ```javascript
   /* Where image is the name of the property sent from angular via the Form Data and the 1 is the max number of files to upload*/
   app.post('/api/v1/upload', upload.array('image', 1), (req, res) => {
    /* This will be th 8e response sent from the backend to the frontend */
    res.send({ image: req.file });
   });
   ```
4) Inside of the <i>file-upload.js</i> paste the following code:

<i>Note: don't forget to change the regions and s3 bucket name in the following code.</i>

   ```javascript
   const aws = require('aws-sdk');
   const multer = require('multer');
   const multerS3 = require('multer-s3');
   const dotenv = require('dotenv');
   dotenv.config();

   aws.config.update({
    secretAccessKey: process.env.SECRET_ACCESS_KEY,
    accessKeyId: process.env.ACCESS_KEY_ID,
    region: 'YOUR AWS REGION' //E.g us-east-1
   });
   
   const s3 = new aws.S3();

   /* In case you want to validate your file type */
   const fileFilter = (req, file, cb) => {
    if (file.mimetype === 'image/jpeg' || file.mimetype === 'image/png') {
     cb(null, true);
    } else {
     cb(new Error('Wrong file type, only upload JPEG and/or PNG !'), 
     false);
    }
   };

   const upload = multer({
   fileFilter: fileFilter,
   storage: multerS3({
    acl: 'public-read',
    s3,
    bucket: 'YOUR S3 BUCKET NAME',
    key: function(req, file, cb) {
      /*I'm using Date.now() to make sure my file has a unique name*/
      req.file = Date.now() + file.originalname;
      cb(null, Date.now() + file.originalname);
     }
    })
   });

   module.exports = upload;
   ```
5) Lastly, in your <i>server.js</i> file, add the following line at the top of the file:
   ```javascript
   const upload = require('./middleware/file-upload');
   ```

<center><h2>Time to test our app</h2></center>

1) Navigate to your BACKEND folder and run the following command in your terminal to start your backend server:
   ```javascript
   npm start
   ```  
2) Navigate to your angular app folder and run the following command in your terminal to start your backend server:
   ```javascript
   ng serve --o
   ``` 
<i>Note: Make sure your backend and frontend servers are running.</i>

3) In your browser where you angular app, upload an image. You should see the following:

<img src="https://thepracticaldev.s3.amazonaws.com/i/z8l4yus990wutvk3g3kk.png" />



<img src="https://thepracticaldev.s3.amazonaws.com/i/5a87eog40zvcsimuaew4.png" />