Hi,
I would need some help with Uppy.
I have created custom URL called /api/invitation/upload, my code using Node and Express:
const envVars = require('../../../config/env-vars');
const express = require('express');
const aws = require('aws-sdk');
const multer = require('multer');
const multerS3 = require('multer-s3');
const bucket = envVars.AWS_S3_BUCKET;
const router = express.Router();
aws.config.update({
accessKeyId: envVars.AWS_ACCESS_KEY_ID,
secretAccessKey: envVars.AWS_SECRET_ACCESS_KEY,
signatureVersion: 'v4',
region: 'eu-west-2',
});
const s3 = new aws.S3();
// Middleware multer for handling multipart/form-data and multer-s3
// to save directly to AWS instead of locally
const upload = multer({
storage: multerS3({
s3,
bucket,
// Set public read permissions
acl: 'public-read',
// Auto detect content type
contentType: multerS3.AUTO_CONTENT_TYPE,
// Set key/filename as original uploaded name
key: (req, file, cb) => {
cb(null, `${Date.now().toString()}-${file.originalname}`);
},
}),
});
router.post('/api/invitation/upload', upload.single('image'), (req, res, next) => {
res.status(200).json({
method: 'post',
url: req.file.location,
fields: [],
});
});
module.exports = router;
By using Paw I am posting file to URL mentioned with folowing
Content-Type: multipart/form-data; charset=utf-8; boundary=__X_PAW_BOUNDARY__
Content-Disposition: form-data; name="image"; filename="some-file-name.png"
Content-Type: image/png
The file gets successfully uploaded to my bucket.
Now I am trying to post with Uppy with following config:
getUploadParameters(file) {
// Send a request to our signing endpoint
return fetch('/api/invitation/upload', {
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) => {
console.log('>>>', data);
// Return an object in the correct shape.
return {
method: data.method,
url: data.url,
fields: data.fields,
};
});
},
}
But getting server error, there is a req.file undefined. What am I missing here or doing wrong? Thank you for the help in advance.
It looks like you are using the AwsS3 upload plugin. This plugin handles uploading in the browser; it does not upload to your own server, but to S3 directly. multer-s3 handles uploading on the server, it expects that you upload the file to your own server and then multer uploads it to S3.
You can either use multer-s3 with the XHRUpload plugin, or use the AwsS3 plugin, but not multer-s3 with the AwsS3 plugin.
When using the AwsS3 plugin, you are expected to return upload parameters, that means a request method, URL, form fields and headers that can be used to do the upload from the browser. uppy-server can create these upload parameters, or you can use a custom endpoint. This example uses a custom PHP endpoint, but it's quite similar in Node:
var url = s3.getSignedUrl('putObject', { Bucket, Key, ContentType, Body: '' })
return {
url,
method: 'PUT',
fields: {},
}
Hope that makes sense!
Hi, thank you for the help, it works!
I will post code, if somebody needs it in the future. Can you change the issue title, that it is clear that it involves Node? Thanks.
const envVars = require('../../../../config/env-vars');
const express = require('express');
const aws = require('aws-sdk');
const bucket = envVars.AWS_S3_BUCKET;
const router = express.Router();
aws.config.update({
accessKeyId: envVars.AWS_ACCESS_KEY_ID,
secretAccessKey: envVars.AWS_SECRET_ACCESS_KEY,
signatureVersion: 'v4',
region: 'eu-west-2',
});
const s3 = new aws.S3();
router.post('/api/invitation/upload', (req, res) => {
const params = {
Bucket: bucket,
Key: `${Date.now().toString()}-${req.body.filename}`,
ContentType: req.body.contentType,
};
s3.getSignedUrl('putObject', params, (err, url) => {
res.status(200).json({
method: 'put',
url,
fields: {},
});
});
});
module.exports = router;
@be-codified really appreciate you posting your code - hugely helpful!
Wonder if you could post your front end js? I'm using your getUploadParameters above with your backend subsequent post but I cannot access the filename for the AWS key: req.body.filename is undefined.
To answer my own question, my solution was to change the header in the client side Uppy config code from:
headers: {
'content-type': 'application/json',
},
to:
headers: {
'content-type': 'application/x-www-form-urlencoded'
},
Then on the Nodejs server side, it returns:
{"filename":"file name.txt","contentType":"text/plain"}': '' })
So I used this to extract the file name:
JSON.parse(Object.keys(req.body)[0]).filename
Which I incorporated into the code which produces the key (i.e. file name) in the AWS S3 bucket:
Key: `${Date.now().toString()}-${JSON.parse(Object.keys(req.body)[0]).filename}`,
More detailed write up on the Uppy support site here.
Most helpful comment
Hi, thank you for the help, it works!
I will post code, if somebody needs it in the future. Can you change the issue title, that it is clear that it involves Node? Thanks.