Add example for Uppy with S3 and a Node.js server (#4129)

Co-authored-by: Merlijn Vos <merlijn@soverin.net>
Co-authored-by: Antoine du Hamel <duhamelantoine1995@gmail.com>
This commit is contained in:
Raúl Ibáñez 2022-10-17 21:43:00 +02:00 committed by GitHub
parent a3153813fa
commit 3f07d79de6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 366 additions and 15 deletions

View file

@ -192,7 +192,7 @@ module.exports = {
'*.mjs',
'e2e/clients/**/*.js',
'examples/aws-companion/*.js',
'examples/aws-presigned-url/*.js',
'examples/aws-php/*.js',
'examples/bundled/*.js',
'examples/custom-provider/client/*.js',
'examples/digitalocean-spaces/*.js',

2
.gitignore vendored
View file

@ -19,7 +19,7 @@ dist/
lib/
coverage/
examples/dev/bundle.js
examples/aws-presigned-url/vendor/*
examples/aws-php/vendor/*
test/endtoend/create-react-app/build/
test/endtoend/create-react-app/coverage/
uppy-*.tgz

View file

@ -312,7 +312,7 @@ Released: 2022-08-02
- @uppy/transloadit: send `assembly-cancelled` only once (Antoine du Hamel / #3937)
- meta: `keepNames` in bundle (Antoine du Hamel / #3926)
- meta: e2e: fix Transloadit test suite with Cypress 10 (Antoine du Hamel / #3936)
- meta: Bump guzzlehttp/guzzle from 7.4.1 to 7.4.5 in /examples/aws-presigned-url (dependabot[bot] / #3842)
- meta: Bump guzzlehttp/guzzle from 7.4.1 to 7.4.5 in /examples/aws-php (dependabot[bot] / #3842)
- @uppy/tus: fix dependencies (Antoine du Hamel / #3923)
- meta: doc: fix linter failure in `image-editor.md` (Antoine du Hamel / #3924)
- meta: doc: Fix typo in image-editor.md (Ikko Ashimine / #3921)
@ -841,7 +841,7 @@ Released: 2022-01-10
- @uppy/tus: pause all requests in response to server rate limiting (Antoine du Hamel / #3394)
- @uppy/transloadit: better defaults for rate limiting (Antoine du Hamel / #3414)
- @uppy/companion: Fix Companion deploys (kiloreux / #3388)
- meta: update aws-presigned-url example to use esm (Antoine du Hamel / #3413)
- meta: update aws-php example to use esm (Antoine du Hamel / #3413)
- @uppy/image-editor: namespace input range css (Merlijn Vos / #3406)
- @uppy/screen-capture: Add missing option to the screen capture types (Mustafa Navruz / #3400)
- @uppy/drag-drop: fix `undefined is not a function` TypeError (Antoine du Hamel / #3397)

View file

@ -0,0 +1,102 @@
# Uppy + AWS S3 with Node.JS
A simple and fully working example of Uppy and AWS S3 storage with Node.js (and Express.js) It uses presigned URL at the backend level.
This README file starts with AWS as this one need to be resolved first.
# AWS Configuration
It's assumed that you are familiar with AWS, at least, with the storage service (S3) and users & policies (IAM).
These instructions are not fit for production but tightening the security is out of the scope here.
## S3 Setup
- Create new S3 bucket in AWS (e.g. `aws-nodejs`).
- Add a bucket policy.
```{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicAccess",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::aws-nodejs/*"
}
]
}
```
- Make the S3 bucket public.
- Add CORS configuration.
```[
{
"AllowedHeaders": [
"*"
],
"AllowedMethods": [
"GET",
"PUT",
"HEAD",
"POST",
"DELETE"
],
"AllowedOrigins": [
"*"
],
"ExposeHeaders": []
}
]
```
## AWS Credentials
You may use existing AWS credentials or create a new user in the IAM page.
- Make sure you setup the AWS credentials properly and write down the Access Key ID and Secret Access Key.
- You may configure AWS S3 credentials using [environment variables](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/loading-node-credentials-environment.html) or a [credentials file in `~/.aws/credentials`](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html).
- You will need at least `PutObject` and `PutObjectAcl` permissions.
```{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:PutObjectAcl"
],
"Resource": "arn:aws:s3:::aws-nodejs/*"
}
]
}
```
# Install
Download this code or clone repository into a folder and install dependencies:
```bash
corepack yarn install
```
Add a `.env` file to the root directory and define the S3 bucket name and port variables like the example below:
```
S3_BUCKET=aws-nodejs
PORT=8080
```
# Enjoy it
Start the application:
```bash
corepack yarn workspace @uppy-example/aws-nodejs start
```
Dashboard demo should now be available at http://localhost:8080.
You have also a Drag & Drop demo on http://localhost:8080/drag.
*Feel free to check how the demo works and feel free to open an issue.*

View file

@ -0,0 +1,53 @@
require('dotenv').config({ path: path.join(__dirname, '..', '..', '.env') })
const express = require('express')
const app = express()
const path = require('node:path')
const port = process.env.PORT
const bodyParser = require('body-parser')
const aws = require('aws-sdk')
app.use(bodyParser.json())
app.get('/', (req, res) => {
const htmlPath = path.join(__dirname, 'public', 'index.html')
res.sendFile(htmlPath)
})
app.get('/drag', (req, res) => {
const htmlPath = path.join(__dirname, 'public', 'drag.html')
res.sendFile(htmlPath)
})
app.post('/sign-s3', (req, res) => {
const s3 = new aws.S3()
const fileName = req.body.filename
const { contentType } = req.body
const s3Params = {
Bucket: process.env.S3_BUCKET,
Key: fileName,
Expires: 60,
ContentType: contentType,
ACL: 'public-read',
}
s3.getSignedUrl('putObject', s3Params, (err, data) => {
if (err) {
console.log(err)
return res.end()
}
const returnData = {
url: data,
method: 'PUT',
}
res.write(JSON.stringify(returnData))
res.end()
})
})
app.listen(port, () => {
console.log(`Example app listening on port ${port}`)
})

View file

@ -0,0 +1,17 @@
{
"name": "@uppy-example/aws-nodejs",
"version": "1.0.0",
"description": "Uppy for AWS S3 with a custom Node.js backend for signing URLs",
"main": "index.js",
"scripts": {
"start": "node index.js"
},
"author": "",
"license": "MIT",
"dependencies": {
"aws-sdk": "^2.1038.0",
"body-parser": "^1.20.0",
"dotenv": "^16.0.0",
"express": "^4.18.1"
}
}

View file

@ -0,0 +1,85 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Uppy</title>
<link href="https://releases.transloadit.com/uppy/v3.0.1/uppy.min.css" rel="stylesheet">
</head>
<body>
<section class="example">
<div id="drag-drop-area"></div>
<div class="for-ProgressBar"></div>
<div class="uploaded-files">
<h5>Uploaded files:</h5>
<ol></ol>
</div>
<script type="module">
import {Uppy, DragDrop, ProgressBar, AwsS3 } from "https://releases.transloadit.com/uppy/v3.0.2/uppy.min.mjs"
// Function for displaying uploaded files
const onUploadSuccess = (elForUploadedFiles) => (file, response) => {
const url = response.uploadURL
const fileName = file.name
const li = document.createElement('li')
const a = document.createElement('a')
a.href = url
a.target = '_blank'
a.appendChild(document.createTextNode(fileName))
li.appendChild(a)
document.querySelector(elForUploadedFiles).appendChild(li)
}
var uppy = new Uppy({
autoProceed: true,
restrictions: {
maxNumberOfFiles: 10,
}
})
.use(DragDrop, {
inline: true,
target: '#drag-drop-area'
})
.use(ProgressBar, { target: '.example .for-ProgressBar', hideAfterFinish: true })
.use(AwsS3, {
getUploadParameters (file) {
// Send a request to our PHP signing endpoint.
return fetch('/sign-s3', {
method: 'post',
// Send and receive JSON.
headers: {
accept: 'application/json',
'content-type': 'application/json',
},
body: JSON.stringify({
filename: file.name,
contentType: file.type,
}),
}).then((response) => {
// Parse the JSON response.
return response.json()
}).then((data) => {
// Return an object in the correct shape.
return {
method: data.method,
url: data.url,
fields: data.fields,
// Provide content type header required by S3
headers: {
'Content-Type': file.type,
},
}
})
},
});
uppy.on('complete', (result) => {
console.log('Upload complete! Weve uploaded these files:', result.successful)
});
uppy.on('upload-success', onUploadSuccess('.example .uploaded-files ol'));
</script>
</section>
</body>
</html>

View file

@ -0,0 +1,58 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Uppy</title>
<link href="https://releases.transloadit.com/uppy/v3.0.1/uppy.min.css" rel="stylesheet">
</head>
<body>
<div id="drag-drop-area"></div>
<script type="module">
import { Uppy, Dashboard, AwsS3 } from "https://releases.transloadit.com/uppy/v3.0.2/uppy.min.mjs"
var uppy = new Uppy()
.use(Dashboard, {
inline: true,
target: '#drag-drop-area',
})
.use(AwsS3, {
getUploadParameters (file) {
// Send a request to our PHP signing endpoint.
return fetch('/sign-s3', {
method: 'post',
// Send and receive JSON.
headers: {
accept: 'application/json',
'content-type': 'application/json',
},
body: JSON.stringify({
filename: file.name,
contentType: file.type,
}),
}).then((response) => {
// Parse the JSON response.
return response.json()
}).then((data) => {
// Return an object in the correct shape.
return {
method: data.method,
url: data.url,
fields: data.fields, // For presigned PUT uploads, this should be left empty.
// Provide content type header required by S3
headers: {
'Content-Type': file.type,
},
}
})
},
});
uppy.on('complete', (result) => {
console.log('Upload complete! Weve uploaded these files:', result.successful)
})
uppy.on('upload-success', (file, data) => {
console.log('Upload success! Weve uploaded this file:', file.meta['name'])
})
</script>
</body>
</html>

View file

@ -1,5 +1,5 @@
{
"name": "@uppy-example/aws-presigned-url",
"name": "@uppy-example/aws-php",
"version": "0.0.0",
"dependencies": {
"@uppy/aws-s3": "workspace:*",

View file

@ -17,7 +17,7 @@ This example also uses the AWS PHP SDK.
To install it, [get composer](https://getcomposer.org) and run `composer update` in this folder.
```bash
corepack yarn workspace @uppy-example/aws-presigned-url exec "composer update"
corepack yarn workspace @uppy-example/aws-php exec "composer update"
```
Configure AWS S3 credentials using [environment variables](https://docs.aws.amazon.com/aws-sdk-php/v3/guide/guide/credentials.html#environment-credentials) or a [credentials file in `~/.aws/credentials`](https://docs.aws.amazon.com/aws-sdk-php/v3/guide/guide/credentials.html#credential-profiles).
@ -26,7 +26,7 @@ Configure a bucket name and region in the `s3-sign.php` file.
Then, again in the **repository root**, start this example by doing:
```bash
corepack yarn workspace @uppy-example/aws-presigned-url start
corepack yarn workspace @uppy-example/aws-php start
```
The demo should now be available at http://localhost:8080.
@ -37,5 +37,5 @@ You can use a different S3-compatible service like GCS by configuring that servi
AWS_PROFILE="gcs" \
COMPANION_AWS_ENDPOINT="https://storage.googleapis.com" \
COMPANION_AWS_BUCKET="test-bucket-name" \
corepack yarn run example aws-presigned-url
corepack yarn run example aws-php
```

View file

@ -347,7 +347,7 @@ uppy.use(AwsS3, {
})
```
See the [aws-presigned-url example in the uppy repository](https://github.com/transloadit/uppy/tree/main/examples/aws-presigned-url) for a small example that implements both the server-side and the client-side.
See the [aws-php example in the uppy repository](https://github.com/transloadit/uppy/tree/main/examples/aws-php) for a small example that implements both the server-side and the client-side.
### Retrieving presign parameters of the uploaded file

View file

@ -6993,8 +6993,8 @@ __metadata:
"@types/jasmine@file:./private/@types/jasmine::locator=%40uppy-dev%2Fbuild%40workspace%3A.":
version: 0.0.0
resolution: "@types/jasmine@file:./private/@types/jasmine#./private/@types/jasmine::hash=917119&locator=%40uppy-dev%2Fbuild%40workspace%3A."
checksum: cc86c9a338a6943da64fb636e13bdc8f2e41922ae62c3cfd95525b0a0965a28ecd7545173773f2b61a3c30ae70c8eeb9a725eb71fd9006a07a8733ecbac849b9
resolution: "@types/jasmine@file:./private/@types/jasmine#./private/@types/jasmine::hash=cf2699&locator=%40uppy-dev%2Fbuild%40workspace%3A."
checksum: f8900f2d42d5c061a69cebc73bc83950095b354964834ab459dbd144a006f4afa0ffc436cfd5c0e74522f5752a7e30d60e1c6c2f69a184f59a749df405a54cdc
languageName: node
linkType: hard
@ -7007,8 +7007,8 @@ __metadata:
"@types/jasminewd2@file:./private/@types/jasmine::locator=%40uppy-dev%2Fbuild%40workspace%3A.":
version: 0.0.0
resolution: "@types/jasminewd2@file:./private/@types/jasmine#./private/@types/jasmine::hash=fe65e0&locator=%40uppy-dev%2Fbuild%40workspace%3A."
checksum: 028a3a54e144661b64d14b439c585db2ade1a22ba4b21de85cb469afd2f1bf5e78079ab3f3e5c058ed4146e7cef5300e27c8d176d9f168222d88576671608135
resolution: "@types/jasminewd2@file:./private/@types/jasmine#./private/@types/jasmine::hash=17481a&locator=%40uppy-dev%2Fbuild%40workspace%3A."
checksum: ccc420c3ba7580cc562cb093705871265a961bce06bc366365fb32f9f73b276900d07ceb08591e4974bd40f766acc442145e78a70a0cf41a6dc1621999965073
languageName: node
linkType: hard
@ -7959,9 +7959,9 @@ __metadata:
languageName: unknown
linkType: soft
"@uppy-example/aws-presigned-url@workspace:examples/aws-presigned-url":
"@uppy-example/aws-php@workspace:examples/aws-php":
version: 0.0.0-use.local
resolution: "@uppy-example/aws-presigned-url@workspace:examples/aws-presigned-url"
resolution: "@uppy-example/aws-php@workspace:examples/aws-php"
dependencies:
"@uppy/aws-s3": "workspace:*"
"@uppy/core": "workspace:*"
@ -8202,6 +8202,17 @@ __metadata:
languageName: unknown
linkType: soft
"@uppy-example/uppy-s3-example@workspace:examples/uppy-s3-example":
version: 0.0.0-use.local
resolution: "@uppy-example/uppy-s3-example@workspace:examples/uppy-s3-example"
dependencies:
aws-sdk: ^2.1225.0
body-parser: ^1.20.0
dotenv: ^16.0.2
express: ^4.18.1
languageName: unknown
linkType: soft
"@uppy-example/uppy-with-companion@workspace:examples/uppy-with-companion":
version: 0.0.0-use.local
resolution: "@uppy-example/uppy-with-companion@workspace:examples/uppy-with-companion"
@ -10774,6 +10785,24 @@ __metadata:
languageName: node
linkType: hard
"aws-sdk@npm:^2.1225.0":
version: 2.1225.0
resolution: "aws-sdk@npm:2.1225.0"
dependencies:
buffer: 4.9.2
events: 1.1.1
ieee754: 1.1.13
jmespath: 0.16.0
querystring: 0.2.0
sax: 1.2.1
url: 0.10.3
util: ^0.12.4
uuid: 8.0.0
xml2js: 0.4.19
checksum: 4483fad82f3cf27540b6beeedbb0c3dd8d8e00751cbd1c7f996bc28822d052879db24b2a646ae1add561112051e0f68705ad77eaa16e13f12d51feb67d8094b1
languageName: node
linkType: hard
"aws-sign2@npm:~0.7.0":
version: 0.7.0
resolution: "aws-sign2@npm:0.7.0"
@ -15033,6 +15062,13 @@ __metadata:
languageName: node
linkType: hard
"dotenv@npm:^16.0.2":
version: 16.0.3
resolution: "dotenv@npm:16.0.3"
checksum: afcf03f373d7a6d62c7e9afea6328e62851d627a4e73f2e12d0a8deae1cd375892004f3021883f8aec85932cd2834b091f568ced92b4774625b321db83b827f8
languageName: node
linkType: hard
"dotenv@npm:^7.0.0":
version: 7.0.0
resolution: "dotenv@npm:7.0.0"