Trying to get multer to upload multiple files to Amazon S3. I have been able to achieve this with single file uploads, but for multiple files, I've been running into trouble. There does not seem to be any problem getting the collection of files from the form itself. However, absolutely nothing gets uploaded to S3. I also do not get any error messages that would help me identify the problem. The review information gets posted to the MongoDB database as expected. I've been trying all night, but can't seem to figure out where I am going wrong here. Any thoughts would be appreciated. Thanks!
front-end JS file that submits the form data to the API route:
export const submitReview = async (reviewFormData) => {
try {
const res = await axios({
method: 'POST',
url: '/api/v1/reviews',
data: reviewFormData,
});
if (res.data.status === 'success') {
showAlert('success', 'Great! Thanks for sharing!');
// window.setTimeout(() => {
// location.assign('/');
// }, 1500);
}
} catch (err) {
showAlert('error', err.response.data.message);
}
};
this is what I have in the controller file that I would expect to make the upload work:
const multer = require('multer');
const multerS3 = require('multer-s3-image-transform');
const sharp = require('sharp');
const aws = require('aws-sdk'),
s3 = new aws.S3();
aws.config.update({
secretAccessKey: process.env.AWS_ACCESS_KEY,
accessKeyId: process.env.AWS_KEY_ID,
region: 'us-east-1',
});
const multerFilter = (req, file, cb) => {
if (file.mimetype.startsWith('image')) {
cb(null, true);
} else {
cb(new AppError('Not an image! Please upload images only.', 400), false);
}
};
exports.uploadReviewPhoto = multer({
storage: multerS3({
s3: s3,
acl: 'public-read',
bucket: 'bucketname',
contentType: multerS3.AUTO_CONTENT_TYPE,
fileFilter: multerFilter,
transforms: () =>
sharp().resize(250, 250).withMetadata().jpeg({
progressive: true,
quality: 90,
}),
key: function (req, file, cb) {
cb(null, 'reviewPhotos/' + Date.now().toString());
},
}),
}).array('userPhotos', 10);
Not sure if helpful, but this is the front-end code that gets the information from the form:
if (reviewForm)
reviewForm.addEventListener('submit', (e) => {
e.preventDefault();
const reviewFormData = new FormData();
reviewFormData.set('ship', document.getElementById('ship').value);
reviewFormData.set('rating', document.getElementById('rating').value);
reviewFormData.set(
'ratingDining',
document.getElementById('ratingDining').value
);
reviewFormData.set(
'ratingCabin',
document.getElementById('ratingCabin').value
);
reviewFormData.set(
'ratingKids',
document.getElementById('ratingKids').value
);
reviewFormData.set(
'ratingValue',
document.getElementById('ratingValue').value
);
reviewFormData.set(
'ratingEntertainment',
document.getElementById('ratingEntertainment').value
);
reviewFormData.set(
'userPhotos',
document.getElementById('userPhotos').files
);
reviewFormData.set('sailDate', document.getElementById('sailDate').value);
reviewFormData.set('review', document.getElementById('review').value);
submitReview(reviewFormData);
});
Including this from the router file just to show that I'm calling the function from the POST route:
router
.route('/')
.get(reviewController.getAllReviews)
.post(
authController.restrictTo('user'),
reviewController.uploadReviewPhoto,
reviewController.setShipUserIds,
reviewController.createReview
);