In the tutorial, we show how to use Angular 6 Client to download files/ upload files from Amazon S3 by Node.js RestAPIs server using Multer middleware and AWS-SDK.
Related posts:
– Node.js RestAPIs Download File from Amazon S3
– Node.js RestAPIs Upload file to Amazon S3
– Node.js RestAPIs – Angular 6 HttpClient – Get/Post/Put/Delete requests + Bootstrap 4
– Amazon S3 – Upload/download large files to S3 with SpringBoot Amazon S3
Related pages:
Technologies
- Angular 6
- Node.js/Express
- Express
- Multer
- AWS-SDK
Overview
We create 2 projects: {Node.js, Angular} ->
Demo
Node.js RestAPIs
Project structure ->
– Node.js use AWS-SDK S3 to download/upload files ->
const s3 = new AWS.S3({ accessKeyId: env.AWS_ACCESS_KEY, secretAccessKey: env.AWS_SECRET_ACCESS_KEY, region : env.REGION });
– S3 APIs to download/upload/list files ->
... // -> Do upload Files s3.upload(params, (err, data) => { if (err) { res.status(500).send("Error -> " + err); } res.send("File uploaded successfully! -> keyname = " + req.file.originalname); }); ... // -> Do download Files s3.getObject(params) .createReadStream() .on('error', function(err){ res.status(500).json({error:"Error -> " + err}); }).pipe(res); // -> List all Files s3.listObjectsV2(params, (err, data) => { if (err) { console.log(err, err.stack); // an error occurred res.send("error -> "+ err); } else { var contents = data.Contents; contents.forEach(function (content) { keys.push(content.Key); }); res.send(keys); } });
– Node.js exposes RestAPIs to download/upload/list files ->
router.post('/api/files/upload', upload.single("file"), awsWorker.doUpload);
router.get('/api/files/all', awsWorker.listKeyNames);
router.get('/api/files/:filename', awsWorker.doDownload);
– Configure cross-origin for Angular-Client which running at port: 4200
->
const cors = require('cors') const corsOptions = { origin: 'http://localhost:4200', optionsSuccessStatus: 200 } app.use(cors(corsOptions))
Angular 6 Client
Project structure ->
– upload-file.service
provides methods: push File to Storage and get Files.
– list-upload.component
gets and displays list of Files.
– form-upload.component
helps upload File.
– details-upload.component
is detail for each item in list of Files.
Practice
Node.js RestAPIs
Setting up Node.js project
Create a folder NodejsUploadDownloadFileAmazonS3
, then init Node.js project ->
>npm init This utility will walk you through creating a package.json file. It only covers the most common items, and tries to guess sensible defaults. See `npm help json` for definitive documentation on these fields and exactly what they do. Use `npm install` afterwards to install a package and save it as a dependency in the package.json file. Press ^C at any time to quit. package name: (nodejsuploaddownloadfileamazons3) version: (1.0.0) description: Node.js Express RestAPIs upload/download/list file to/from Amazon S3 using Multer, AWS-SDK entry point: (index.js) server.js test command: git repository: keywords: Nodejs, Express, Amazon S3, RestAPI, Upload File, Download File, List File, Multer, Aws SDK author: ozenero.com license: (ISC) About to write to D:\gkz\article\NodejsUploadDownloadFileAmazonS3\package.json: { "name": "nodejsuploaddownloadfileamazons3", "version": "1.0.0", "description": "Node.js Express RestAPIs upload file, download file, list files to Amazon S3 using Multer, AWS-SDK", "main": "server.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [ "Nodejs", "Express", "Amazon", "S3", "RestAPI", "UploadFile", "DownloadFile", "Multer", "Aws", "SDK" ], "author": "ozenero.com", "license": "ISC" } Is this ok? (yes) yes
Install Express, Multer, Cors, AWS-SDK ->
npm install express multer cors aws-sdk --save
-> package.json
file:
{ "name": "nodejsuploaddownloadfileamazons3", "version": "1.0.0", "description": "Nodejs Express RestAPIs uploads file/downloads file from Amazon S3", "main": "server.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [ "Nodejs", "Express", "RestAPI", "DownloadFile", "Amazon", "S3", "AWS-SDK", "Multer", "Cors" ], "author": "ozenero.com", "license": "ISC", "dependencies": { "aws-sdk": "^2.302.0", "cors": "^2.8.4", "express": "^4.16.3", "multer": "^1.3.1" } }
Multer Config
– Create ./app/config/multer.config.js
file:
const multer = require('multer'); var storage = multer.memoryStorage() var upload = multer({storage: storage}); module.exports = upload;
AWS S3 Config
– Create a file ./app/config/s3.env.js
->
const env = { AWS_ACCESS_KEY: 'AKIAI7PUDS2W5HMSVQRA', // change to yours AWS_SECRET_ACCESS_KEY: '5xmrnGFK7klMGQovhFNssJE96j4NN4F3xFi7wBc1', // change to yours REGION : 'us-east-2', // change to yours Bucket: 'ozenero-s3-bucket' // change to yours }; module.exports = env;
– Configure S3 Client in a file ./app/config/s3.config.js
->
const AWS = require('aws-sdk'); const env = require('./s3.env.js'); const s3 = new AWS.S3({ accessKeyId: env.AWS_ACCESS_KEY, secretAccessKey: env.AWS_SECRET_ACCESS_KEY, region : env.REGION }); module.exports = s3;
Express Routers
– Create router in file ./app/routers/s3.router.js ->
let express = require('express'); let router = express.Router(); let upload = require('../config/multer.config.js'); const awsWorker = require('../controllers/s3.controller.js'); router.post('/api/files/upload', upload.single("file"), awsWorker.doUpload); router.get('/api/files/all', awsWorker.listKeyNames); router.get('/api/files/:filename', awsWorker.doDownload); module.exports = router;
Upload/Download/List Files Controller
– Implement S3 Uploader in a controller file ./app/controllers/s3.controller.js
->
const s3 = require('../config/s3.config.js'); const env = require('../config/s3.env.js'); exports.doUpload = (req, res) => { const params = { Bucket: env.Bucket, Key: req.file.originalname, Body: req.file.buffer } s3.upload(params, (err, data) => { if (err) { res.status(500).send("Error -> " + err); } res.send("File uploaded successfully! -> keyname = " + req.file.originalname); }); } exports.listKeyNames = (req, res) => { const params = { Bucket: env.Bucket } var keys = []; s3.listObjectsV2(params, (err, data) => { if (err) { console.log(err, err.stack); // an error occurred res.send("error -> "+ err); } else { var contents = data.Contents; contents.forEach(function (content) { keys.push(content.Key); }); res.send(keys); } }); } exports.doDownload = (req, res) => { const params = { Bucket: env.Bucket, Key: req.params.filename } res.setHeader('Content-Disposition', 'attachment'); s3.getObject(params) .createReadStream() .on('error', function(err){ res.status(500).json({error:"Error -> " + err}); }).pipe(res); }
Server.js
– server.js
->
const express = require('express'); const app = express(); const cors = require('cors') const corsOptions = { origin: 'http://localhost:4200', optionsSuccessStatus: 200 } app.use(cors(corsOptions)) let router = require('./app/routers/s3.router.js'); app.use('/', router); // Create a Server const server = app.listen(8080, function () { let host = server.address().address let port = server.address().port console.log("App listening at http://%s:%s", host, port); })
Angular 6 Client
Generate Service & Components
Run commands below:
ng g s upload/UploadFile
ng g c upload/FormUpload
ng g c upload/ListUpload
ng g c upload/DetailsUpload
On each Component selector, delete app-
prefix, then change tslint.json rules – "component-selector"
to false.
App Module
app.module.ts
->
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { HttpClientModule } from '@angular/common/http'; import { AppComponent } from './app.component'; import { DetailsUploadComponent } from './upload/details-upload/details-upload.component'; import { FormUploadComponent } from './upload/form-upload/form-upload.component'; import { ListUploadComponent } from './upload/list-upload/list-upload.component'; @NgModule({ declarations: [ AppComponent, DetailsUploadComponent, FormUploadComponent, ListUploadComponent ], imports: [ BrowserModule, HttpClientModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
Upload File Service
upload/upload-file.service.ts
->
import { Injectable } from '@angular/core'; import { HttpClient, HttpEvent, HttpRequest } from '@angular/common/http'; import { Observable } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class UploadFileService { constructor(private http: HttpClient) { } pushFileToStorage(file: File): Observable> { const formdata: FormData = new FormData(); formdata.append('file', file); const req = new HttpRequest('POST', '/post', formdata, { reportProgress: true, responseType: 'text' }); return this.http.request(req); } getFiles(): Observable { return this.http.get('/getallfiles'); } }
Component for getting List of Files
upload/list-upload.component.ts
->
import { Component, OnInit } from '@angular/core'; import { Observable } from 'rxjs'; import { UploadFileService } from '../upload-file.service'; @Component({ selector: 'list-upload', templateUrl: './list-upload.component.html', styleUrls: ['./list-upload.component.css'] }) export class ListUploadComponent implements OnInit { showFile = false; fileUploads: Observable; constructor(private uploadService: UploadFileService) { } ngOnInit() { } showFiles(enable: boolean) { this.showFile = enable; if (enable) { this.fileUploads = this.uploadService.getFiles(); } } }
upload/list-upload.component.html
->
List of Files
upload/details-upload.component.ts
->
import { Component, OnInit, Input } from '@angular/core'; @Component({ selector: 'details-upload', templateUrl: './details-upload.component.html', styleUrls: ['./details-upload.component.css'] }) export class DetailsUploadComponent implements OnInit { @Input() fileUpload: string; constructor() { } ngOnInit() { } }
upload/details-upload.component.html
->
{{fileUpload}}
Component for uploading File
upload/form-upload.component.ts
import { Component, OnInit } from '@angular/core'; import { UploadFileService } from '../upload-file.service'; import { HttpResponse, HttpEventType } from '@angular/common/http'; @Component({ selector: 'form-upload', templateUrl: './form-upload.component.html', styleUrls: ['./form-upload.component.css'] }) export class FormUploadComponent implements OnInit { selectedFiles: FileList; currentFileUpload: File; progress: { percentage: number } = { percentage: 0 }; constructor(private uploadService: UploadFileService) { } ngOnInit() { } selectFile(event) { this.selectedFiles = event.target.files; } upload() { this.progress.percentage = 0; this.currentFileUpload = this.selectedFiles.item(0); this.uploadService.pushFileToStorage(this.currentFileUpload).subscribe(event => { if (event.type === HttpEventType.UploadProgress) { this.progress.percentage = Math.round(100 * event.loaded / event.total); } else if (event instanceof HttpResponse) { console.log('File is completely uploaded!'); } }); this.selectedFiles = undefined; } }
upload/form-upload.component.html
->
App Component
app.component.ts
->
import { Component } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { title = 'ozenero'; description = 'Angular-Node.js Demo'; }
app.component.html
->
{{title}}
{{description}}
Run & Check Results
Run Node.js Server (using npm start
) and Angular 6 Client App (using ng serve
)
Then open Browser with url http://localhost:4200/
.
-> Upload files and show list of Files:
-> Amazon S3 Files:
-> Click to the links to download files:
SourceCode
– NodejsUploadDownloadFileAmazonS3
– Angular-6-Upload-Download-Files