How can Amazon S3 be used to generate a public link in a web application developed with Angular 4?

Currently, I am working on a web application utilizing Angular 4 with TypeScript language as the foundation. The backend of this application is established on AWS.

My knowledge of TypeScript (JavaScript) methods for calling procedures to interact with AWS services is limited. However, the task at hand is quite straightforward. My query pertains to retrieving a link (in string format) after uploading a file, such as an image, to an Amazon S3 Bucket. How can I obtain this link in order to display the image on the webpage?

I aim to develop an internal TypeScript method within my application that generates this link without exposing it using S3 commands.

This method should reference the S3 bucket (specifically the folder name and file name) and produce a public link accessible to all users as a string. Can someone provide guidance on how to accomplish this?

Answer №1

Check out these project files that you are welcome to use. If you have any questions, feel free to ask. I believe the comments provided should be sufficient for understanding:

ANGULAR SERVICE

import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import { Observable } from 'rxjs/Observable';
// Environment is important for the nodeJS API endpoint
import { environment } from '../../../environments/environment';

@Injectable()
export class S3UploadService {

  constructor(private http: Http, private session: SessionManagerService) { }

  /**
   * Retrieves a signed request from AWS
   * @param file The file to be uploaded
   */
  getSignedRequest(file: File): Observable<{ signedRequest: string, url: string }> {
    // Generating a unique name: 8 random characters, user ID, timestamp, extension. Ensuring uniqueness.
    let name = Math.random().toString(36).substr(2, 8)
      + '-' + Parse.User.current().id + '-'
      + new Date().getTime().toString() + '.'
      + file.name.split('.').pop();
    return this.http.get(`${environment.remoteUrl}sign-s3?file-name=${name}&file-type=${file.type.toLowerCase()}`)
      .map(data => data.json())
      .catch(err => Observable.throw(err));
  }

  /**
   * Sends a file to Amazon for uploading
   * @param file The file being uploaded
   * @param signedRequest The signed request obtained from getSignedRequest method
   * @param url The URL of the file on AWS
   */
  uploadFile(file: File, signedRequest: string, url: string): Observable<{ url: string }> {
    // No json() function needed here as Amazon does not send json responses.
    return this.http.put(signedRequest, file)
      .map(data => {
        // Removing the signature portion
        data.url = data.url.split('?')[0];
        return data;
      })
      .catch(err => Observable.throw(err));
  }
}

NODEJS ENDPOINT

// Obtain a signed request from Amazon.
app.get('/sign-s3', function(req, res) {
  const s3 = new aws.S3();
  const fileName = req.query['file-name'];
  const fileType = req.query['file-type'];
  const s3Params = {
    Bucket: S3_BUCKET,
    Key: fileName,
    Expires: 60,
    ContentType: fileType,
    ACL: 'public-read'
  };
  s3.getSignedUrl('putObject', s3Params, function(err, data) {
    if (err) {
      console.log('Error occurred : \n' + err);
      return res.status(500).send(JSON.stringify({ message: 'Internal Server Error' }));
    }
    const returnData = {
      signedRequest: data,
      url: 'https://' + S3_BUCKET + '.s3.amazonaws.com/' + fileName
    };
    res.write(JSON.stringify(returnData));
    res.end();
  });
});

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Guide to retrieving the file URL after uploading it using the AWS S3 PHP API

Recently, I utilized the AWS SDK from https://github.com/aws/aws-sdk-php. Here is a snippet of the code I used: $result = $client->putObject(array( 'Bucket' => $bucket, 'Key' => $key, 'Body&apo ...

Vue 3 Composable console error: Unable to access properties of undefined (specifically 'isError') due to TypeError

I recently developed a Vue 3 / TypeScript Composable for uploading images to Firebase storage. The code snippet below illustrates the structure of the ImageUpload interface: interface ImageUpload { uploadTask?: UploadTask; downloadURL?: string; progr ...

Angular 4: Implementing Subscription with Behavior Subject

I am currently working with Angular 4 and utilizing observables. I have a requirement to share data between components as I am using BehaviorSubject along with observables. Below is the code snippet: import { Subject } from 'rxjs/Subject'; imp ...

Add a dynamic version variable to the script tag and stylesheet based on the current time

<script src="/assets/abc.js?v='+new Date.getTime();" type="text/javascript"></script> <link href="/assets/cder.css?v='+new Date.getTime();" rel="stylesheet"></link> alternatively, var myVariable = Math.floor(Math.rando ...

Higher Order Function with Generics

I am looking to create a special function that can generate a constructor function for one of my existing React components. The result will be a customized class extension of the component passed into it. In simple terms: The output of my higher-order fu ...

Data retrieval from client-side fetch request results in a corrupted file upon download

I'm facing an issue while attempting to fetch a file using a GET request and download it directly in the browser. However, after the download is complete and I try to open the file, it seems to be corrupted. Strangely, only .txt files are opening corr ...

Angular 2 - Oops! The "app-root" selector isn't finding any elements to match

Currently diving into Angular 2 with no prior experience in Angular. I came across this tutorial: . After implementing a new component called "app-people-list" and making the necessary update in index.html, I encountered the following exception. Can anyon ...

Can you please provide the Typescript type of a route map object in hookrouter?

Is there a way to replace the 'any' type in hookrouter? type RouteMap = Record<string, (props?: any) => JSX.Element>; Full Code import { useRoutes, usePath, } from 'hookrouter' //// HOW DO I REPLACE any??? type RouteMap = ...

Angular application integration with three.js OrthographicTrackballControls

Has anyone successfully integrated the OrthographicTrackballControls from three.js with Angular 4? I attempted to do so by running: npm install --save three-orthographic-trackball-controls Then in my component: import { OrthographicTrackballControls } f ...

Utilizing Observables for data filtration

I'm working with an array of objects that I want to filter. I had the idea to use Observables for this task. Can anyone confirm if this approach is correct? export class MyClass { public item1: string; public item2: string; } let myArray = M ...

Issue with Angular 2 view not refreshing after receiving ipcRenderer.on event in Electron

Utilizing ipcRenderer to fetch the folder path from a browser dialog in my main.js. However, it is not updating the text string on my view for some unknown reason. I am aware that using setTimeout could potentially fix this issue (thanks Google!). Yet, e ...

Updating Radio Button Value in React Using TypeScript Event Handler

Whenever I try to save different values to the state, I encounter an issue where selecting female results in the male radio button being selected, and vice versa. Do you think it would be better to use a generic 'gender' variable in the state in ...

What are some ways to create a dynamic child server component?

Take a look at the following code snippet // layout.tsx export default function Layout({children}: any) { return <div> {children} </div> } // page.tsx export const dynamic = "force-dynamic"; const DynamicChild = dynamic( ...

Can someone please explain the result of console.log(error) and how can I convert it into a string?

Within a Node.js project that utilizes Typescript and is aimed at ES2020 compatibility, I have implemented a custom Error class in the following manner: class InvalidParamsError extends Error { } try { throw new InvalidParamsError(); } catch (error) { ...

Unable to resolve external modules in TypeScript when using node.js

I wanted to integrate moment.js into my node application, so I proceeded by installing it using npm: npm install <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="adc0c2c0c8c3d9ed9f8399839d">[email protected]</a> J ...

Creating dynamic form fields with Angular 8's reactive forms

I'm struggling with populating form fields from an array. My initial approach was to input the array into a single component that would manage the form instead of creating multiple forms. However, I can't seem to make it work. Any assistance woul ...

Adding personalized typings to a JHipster (v5.82) application

Starting a new JHipster project (v5.8.2) and integrating the Metronic Angular theme can be a bit of a challenge, especially with limited documentation available. After integrating the various css/js bundles and components, I encountered an issue with some ...

Exploring the process of looping through S3 bucket items and delivering notifications to SQS

I've successfully developed a function that retrieves messages from an SQS Dead Letter Queue (DLQ) and uploads them to an S3 bucket. Now, my goal is to create another function or method to resend these messages from the S3 bucket. Currently, I'm ...

The specified 'currency' pipe was not found during Ahead of Time compilation (AOT)

Our team recently upgraded an Angular application from version 6 to 7. The application uses the built-in currency pipe, and everything was functioning correctly when running with ng serve or building in development mode. However, problems arose when attem ...

Combining similar property objects within a group

I am facing a similar object structure with the goal of summing up the same property grouped by year (e.g., 2016 --> importo1: 7500, importo2: 0, importo3: 0, importo4: 3000) { index: 0, annoDelibera: 2020, importo1: 2500, importo2: 3000, imp ...