mirror of
https://github.com/transloadit/uppy.git
synced 2026-07-17 16:50:22 +00:00
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:
parent
a3153813fa
commit
3f07d79de6
19 changed files with 366 additions and 15 deletions
|
|
@ -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
2
.gitignore
vendored
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
102
examples/aws-nodejs/README.md
Normal file
102
examples/aws-nodejs/README.md
Normal 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.*
|
||||
53
examples/aws-nodejs/index.js
Normal file
53
examples/aws-nodejs/index.js
Normal 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}`)
|
||||
})
|
||||
17
examples/aws-nodejs/package.json
Normal file
17
examples/aws-nodejs/package.json
Normal 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"
|
||||
}
|
||||
}
|
||||
85
examples/aws-nodejs/public/drag.html
Normal file
85
examples/aws-nodejs/public/drag.html
Normal 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! We’ve uploaded these files:', result.successful)
|
||||
});
|
||||
|
||||
uppy.on('upload-success', onUploadSuccess('.example .uploaded-files ol'));
|
||||
</script>
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
||||
58
examples/aws-nodejs/public/index.html
Normal file
58
examples/aws-nodejs/public/index.html
Normal 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! We’ve uploaded these files:', result.successful)
|
||||
})
|
||||
|
||||
uppy.on('upload-success', (file, data) => {
|
||||
console.log('Upload success! We’ve uploaded this file:', file.meta['name'])
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"name": "@uppy-example/aws-presigned-url",
|
||||
"name": "@uppy-example/aws-php",
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"@uppy/aws-s3": "workspace:*",
|
||||
|
|
@ -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
|
||||
```
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
48
yarn.lock
48
yarn.lock
|
|
@ -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"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue