Article

Upload images from Angular app to AWS s3 bucket using FineUploader

Last updated 
Jan 19, 2019
 min read

This post is intended for web developers who are trying to implement image upload functionality.

If your website needs to allow users to upload images then it is always a good idea to upload them on s3 bucket, instead of your dedicated server. Uploading on s3 will have following benifits:

  • You can store as much data as you want and access it when you need it.
  • You don’t need to worry about backups, if you have stored it on S3.
  • With Amazon S3 you only pay for the storage you actually use. There is no minimum fee and no setup cost.
  • Amazon S3 gives you the ability to store a large amount of data with a very low cost.

Setting Up AWS S3 for FineUploader

To upload images on S3, We need to have AWS_ACCESS_KEY and AWS_SECRET_KEY of aws user who has appropriate permission to upload images in bucket.

Earlier, To store images on s3, developers where used to send file bytes to back-end server and then that server is responsible to upload images to s3 bucket because we can not use AWS_SECRET_KEY in front-end.

But there is a better way possible. We can use Fine Uploader library which allows us to upload images directly to s3 with minimum support of back-end. This library eliminates server side complexity and saves bandwidth.

I will quickly explain how to use this library with angular app.

First of all, we need to create bucket in AWS S3. By default, AWS allows cross-origin GET requests on S3 bucket. This is enforced via an XML document in the CORS configuration. You need to change this configuration to allow POST request on S3 bucket.

1<?xml version=”1.0" encoding=”UTF-8"?>
2<CORSConfiguration xmlns=”http://s3.amazonaws.com/doc/2006-03-01/">
3  <CORSRule>
4    <AllowedOrigin>*</AllowedOrigin>
5    <AllowedMethod>POST</AllowedMethod>
6    <MaxAgeSeconds>3000</MaxAgeSeconds>
7    <AllowedHeader>*</AllowedHeader>
8  </CORSRule>
9</CORSConfiguration>
AWS s3 bucket CORS editor

AWS s3 bucket CORS editor

Go to your Angular project’s directory and run following command.

npm install fine-uploader --save

Now create upload button with unique id in your app component html file.

1<div class=”btn” id=”upload_image”>Upload image</div>

Import fine uploader in your component.ts file.

1import { s3 } from ‘fine-uploader/lib/core/s3’;

FineUploader Configuration Options

Now, you need to initialize fine uploader inside ngAfterViewInit method for your component’s life-cycle. You can set options as per your need. Read detailed explanation about options here.

Sample file to showing fine uploader initialization and setting options:

1import { Component, AfterViewInit, OnInit } from '@angular/core';
2
3import { s3 } from 'fine-uploader/lib/core/s3';
4
5@Component({
6  selector: 'app-root',
7  templateUrl: './app.component.html',
8  styleUrls: ['./app.component.css']
9})
10export class AppComponent implements AfterViewInit{
11  bucketName = 'fineuploader-demo';
12
13  uploader: any;
14
15  ngAfterViewInit() {   
16    let instance = this; 
17    this.uploader = new s3.FineUploaderBasic({
18      button: document.getElementById('upload_image'),
19      debug: false,
20      autoUpload: true,
21      multiple: true,
22      validation: {
23        allowedExtensions: ['jpeg', 'jpg', 'png', 'gif', 'svg'],
24        sizeLimit: 5120000 // 50 kB = 50 * 1024 bytes
25      },
26      region: 'us-west-2',
27      request: {
28        endpoint: 'https://' + instance.bucketName  +'.s3.amazonaws.com/',
29        params: { 'Cache-Control': 'private, max-age=31536000, must-revalidate' }
30      },
31      signature: {
32        endpoint: 'http://localhost:8000/api/v1/fine_uploader/s3_signature/',
33      },
34      iframeSupport: {
35        localBlankPagePath: '/somepage.html'
36      },
37      cors: {
38        expected: true,
39        sendCredentials: true
40      },
41      objectProperties: {
42        acl: 'public-read',       
43      },     
44      callbacks: {
45        onSubmit: function (id, fileName) {
46          console.log('selected file:', fileName);
47        },
48        // onSubmitted: function(id, name) { alert('onSubmitted');},
49        onComplete: function (id, name, responseJSON, maybeXhr) {
50          if(responseJSON.success) {
51            console.log('upload complete', name);
52            console.log('uploaded image url', 'https://' + instance.bucketName + '.s3.amazonaws.com/' + this.getKey(id));
53          }
54        },
55        // onAllComplete: function (successful, failed) { console.log(failed); },
56        // onCancel: function (id, name) {},
57        // onUpload: function(id, name) { alert('onUpload');},
58        // onUploadChunk: function(id, name, chunkData) { alert('onUploadChunk');},
59        // onUploadChunkSuccess: function(id, chunkData, responseJSON, xhr) { alert('onUploadChunkSuccess');},
60        // onResume: function(id, fileName, chunkData) { alert('onResume');},
61        // onProgress: function (id, name, loaded, total) {},
62        // onTotalProgress: function(loaded, total) { alert('onTotalProgress');},
63        // onError: function (id, name, reason, maybeXhrOrXdr) {  },      
64        // onSessionRequestComplete: function (response, success, xhrOrXdr) { }
65      }
66    });
67  }
68}

Also read: Cache Busting for an Angular App Deployed with AWS S3 and CloudFront

Creating the AWS Signature Endpoint (Server-Side)

Take a look at options which I have set here in order to upload images to S3.

  • region : AWS region in which you have created your bucket.
  • request.endpoint : Your bucket url
  • request.accessKey : This should be access key of AWS user who has permission to upload objects into target bucket.
  • objectProperties.acl : This value corresponds to a canned ACL. Here, I have set public-read to make all uploaded images to be publicly readable.
  • signature.endpoint : The endpoint that Fine Uploader can use to send policy documents (HTML form uploads) or other strings to sign (REST requests) before sending requests off to S3. We need to create this endpoint on server side. This endpoint or API will use AWS_ACCESS_KEY and AWS_SECRET_KEY to generate pre-signed post url. We just need to create this endpoint and fine uploader will automatically call this endpoint to get signature and then send image to s3 bucket with pre-signed signature.

Below is the code snippet written in Django to show sample endpoint which generates signature.

1import boto3
2from rest_framework import status
3from rest_framework.response import Response
4from rest_framework.views import APIView
5
6class GenerateAwsSignature(APIView):
7    """Generate an AWS signature for presigned POST requests.
8    This signed data allows file uploads directly from the browser to S3.
9    """
10
11    def post(self, request):
12        """
13        * API to be consumed by fine uploader to upload images directly to s3 bucket.
14   
15        """
16
17        s3 = boto3.client(
18            's3',
19            aws_access_key_id='xxxxxxxxxxxxxxx',
20            aws_secret_access_key='xxxxxxxxxxxxxx')
21        # http://boto3.readthedocs.io/en/latest/reference/services/s3.html#S3.Client.generate_presigned_post
22        try:
23            data = s3.generate_presigned_post(
24                'fineuploader-demo',
25                '${filename}',
26                Conditions=request.data['conditions'],
27                ExpiresIn=60 * 60,
28            )
29        except KeyError:
30            return Response(zo_diageo_response.generate_failure_response(
31                custom_error_codes.INVALID_DATA_1204),
32                status=status.HTTP_400_BAD_REQUEST)
33
34        return Response({'policy': data['fields']['policy'],
35                         'signature': data['fields']['signature'],
36                         'url': data['url']},
37                        status=status.HTTP_200_OK)

Done. You can check running your front-end app and click on that upload button which we have created. Your selected files will be uploaded to S3 and you will see uploaded image urls in your browser’s console.

That’s it. Thank you for reading.

Also read: Dynamically Adding and Removing Form Fields in Angular's Reactive Forms with FormArray

Authors

Hiren Patel

Software Engineer
My skills includes full stack web development and can also work on deployment and monitoring of web application on a server. The kind of work that I can do and have experience : Back-end: 1. Python scripting 2. Django Rest framework to create REST APIs 3. Writing unit test case and use automation to test build before deployment Front-end: 1. Web application development using Angular 2/4/6 Framework 2. Challenging UI development using HTML5, CSS3 3. CSS, Jquery and SVG animations Others: 1. AWS ec2, s3, RDS, ECS, CI-CD with AWS, 2.Jenkins

Tags

No items found.

Have a project in mind?

Read