Uploading image to amazon s3 using multer-s3 nodejs
Solution 1
[Update Mar 2022] It works perfectly fine till-date and now also shows the uploaded file public URL as well.
Complete and working Node Cheat | Upload to s3 using multer-s3 available.
Code:
var express = require('express'),
aws = require('aws-sdk'),
bodyParser = require('body-parser'),
multer = require('multer'),
multerS3 = require('multer-s3');
aws.config.update({
secretAccessKey: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
accessKeyId: 'XXXXXXXXXXXXXXX',
region: 'us-east-1'
});
var app = express(),
s3 = new aws.S3();
app.use(bodyParser.json());
var upload = multer({
storage: multerS3({
s3: s3,
acl: 'public-read',
bucket: 'bucket-name',
key: function (req, file, cb) {
console.log(file);
cb(null, file.originalname); //use Date.now() for unique file keys
}
})
});
//open in browser to see upload form
app.get('/', function (req, res) {
res.sendFile(__dirname + '/index.html');//index.html is inside node-cheat
});
//use by upload form
app.post('/upload', upload.array('upl', 25), function (req, res, next) {
res.send({
message: "Uploaded!",
urls: req.files.map(function(file) {
return {url: file.location, name: file.key, type: file.mimetype, size: file.size};
})
});
});
app.listen(3000, function () {
console.log('Example app listening on port 3000!');
});
For complete repo:
Clone node-cheat express_multer_s3, run node app
followed by npm install express body-parser aws-sdk multer multer-s3
.
Happy Helping!
Solution 2
@V31 has answered very well still I want to add my 2 cents.
I believe in keeping one responsibility into one file, for better code organization and debugging purpose.
I have created a file for uploading upload.js
.
require('dotenv').config();
const AWS = require('aws-sdk');
const multer = require('multer');
const multerS3 = require('multer-s3');
const s3Config = new AWS.S3({
accessKeyId: process.env.AWS_IAM_USER_KEY,
secretAccessKey: process.env.AWS_IAM_USER_SECRET,
Bucket: process.env.AWS_BUCKET_NAME
});
const fileFilter = (req, file, cb) => {
if (file.mimetype === 'image/jpeg' || file.mimetype === 'image/png') {
cb(null, true)
} else {
cb(null, false)
}
}
// this is just to test locally if multer is working fine.
const storage = multer.diskStorage({
destination: (req, res, cb) => {
cb(null, 'src/api/media/profiles')
},
filename: (req, file, cb) => {
cb(null, new Date().toISOString() + '-' + file.originalname)
}
})
const multerS3Config = multerS3({
s3: s3Config,
bucket: process.env.AWS_BUCKET_NAME,
metadata: function (req, file, cb) {
cb(null, { fieldName: file.fieldname });
},
key: function (req, file, cb) {
console.log(file)
cb(null, new Date().toISOString() + '-' + file.originalname)
}
});
const upload = multer({
storage: multerS3Config,
fileFilter: fileFilter,
limits: {
fileSize: 1024 * 1024 * 5 // we are allowing only 5 MB files
}
})
exports.profileImage = upload;
Which is imported inside my routes routes.js
const express = require('express');
const ProfileController = require('../profile/controller');
const { profileImage } = require('../utils/upload.js');
const routes = (app) => {
const apiRoutes = express.Router();
apiRoutes.use('/profile', profileRoutes);
profileRoutes.post('/',profileImage.single('profileImage'), ProfileController.saveProfile);
app.use('/api', apiRoutes);
}
module.exports = routes
Postman screen shot for post body
Solution 3
I just want to add my cents,
There are many comments in all answers like how to get public URL after uploading and S3 response object and lets see implementation and cases,
// INITIALIZE NPMS
var AWS = require('aws-sdk'),
multer = require('multer'),
multerS3 = require('multer-s3'),
path = require('path');
// CONFIGURATION OF S3
AWS.config.update({
secretAccessKey: '***********************************',
accessKeyId: '****************',
region: 'us-east-1'
});
// CREATE OBJECT FOR S3
const S3 = new AWS.S3();
// CREATE MULTER FUNCTION FOR UPLOAD
var upload = multer({
// CREATE MULTER-S3 FUNCTION FOR STORAGE
storage: multerS3({
s3: S3,
acl: 'public-read',
// bucket - WE CAN PASS SUB FOLDER NAME ALSO LIKE 'bucket-name/sub-folder1'
bucket: 'bucket-name',
// META DATA FOR PUTTING FIELD NAME
metadata: function (req, file, cb) {
cb(null, { fieldName: file.fieldname });
},
// SET / MODIFY ORIGINAL FILE NAME
key: function (req, file, cb) {
cb(null, file.originalname); //set unique file name if you wise using Date.toISOString()
// EXAMPLE 1
// cb(null, Date.now() + '-' + file.originalname);
// EXAMPLE 2
// cb(null, new Date().toISOString() + '-' + file.originalname);
}
}),
// SET DEFAULT FILE SIZE UPLOAD LIMIT
limits: { fileSize: 1024 * 1024 * 50 }, // 50MB
// FILTER OPTIONS LIKE VALIDATING FILE EXTENSION
fileFilter: function(req, file, cb) {
const filetypes = /jpeg|jpg|png/;
const extname = filetypes.test(path.extname(file.originalname).toLowerCase());
const mimetype = filetypes.test(file.mimetype);
if (mimetype && extname) {
return cb(null, true);
} else {
cb("Error: Allow images only of extensions jpeg|jpg|png !");
}
}
});
There are three cases, if we want to retrieve files res
object from S3 after upload:
Case 1: When we are using .single(fieldname)
method it will return file object in req.file
app.post('/upload', upload.single('file'), function (req, res, next) {
console.log('Uploaded!');
res.send(req.file);
});
Case 2: When we are using .array(fieldname[, maxCount])
method it will return file object in req.files
app.post('/upload', upload.array('file', 1), function (req, res, next) {
console.log('Uploaded!');
res.send(req.files);
});
Case 3: When we are using .fields(fields)
method it will return file object in req.files
app.post('/upload', upload.fields([
{ name: 'avatar', maxCount: 1 },
{ name: 'gallery', maxCount: 8 }
]), function (req, res, next) {
console.log('Uploaded!');
res.send(req.files);
});
Solution 4
s3
needs to be an object to be passed. According to the docs, the object needs to be like this:
var upload = multer({
storage: multerS3({
s3: s3,
bucket: 'some-bucket',
metadata: function (req, file, cb) {
cb(null, {fieldName: file.fieldname});
},
key: function (req, file, cb) {
cb(null, Date.now().toString())
}
})
})
Solution 5
//here is the function for upload the images on aws bucket using multer
const path = require('path');
const fs = require('fs');
const aws = require('aws-sdk');
const multer = require('multer');
const multerS3 = require('multer-s3');
aws.config.update({
secretAccessKey: '**************************',
accessKeyId: '********************',
region: '**********************'
});
s3 = new aws.S3();
const storage = multerS3({
s3: s3,
bucket: 'bucket-name',
key: function(req, file, cb) {
console.log(file);
cb(null, file.originalname);
}
})
//export the created function
exports.uploadVideo = multer({ storage: storage }).single('file_name');
//================================================================================
//import uploadVideo function whenever you need to upload the file on aws s3 bucket
const { uploadVideo } = require('../../services/upload');
exports.videoUpload = (req, res) => {
uploadVideo(req, res, function(err) {
if (err) {
console.log(err);
res.json({ status: 401, msg: err.message });
} else {
const image = getImagePath(req.file.filename);
res.json({ status: 200, msg: 'Image uploaded sucess.', data: image });
}
});
}
//================================================================================
//here is route file
router.post('/video-upload',uploadController.videoUpload);
mBlaze
Updated on February 22, 2021Comments
-
mBlaze about 3 years
I am trying to upload an image to amazon s3 using
multer-s3
, but I am getting this error:TypeError: Expected opts.s3 to be object node_modules/multer-s3/index.js:69:20
This is my server code:
var upload = multer({ storage: s3({ dirname: '/', bucket: 'bucket', secretAccessKey: 'key', accessKeyId: 'key', region: 'us-west-2', filename: function (req, file, cb) { cb(null, file.originalname); } }) }); app.post('/upload', upload.array('file'), function (req, res, next) { res.send("Uploaded!"); });
Why I am getting this error?
-
mBlaze over 7 yearsWhere to provide the accesskeyId for above
-
V31 over 7 years@mBlaze: you need to create a s3 object using var s3 = new aws.S3({ /* ... */ }) using the aws sdk. you can find more info using the link docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/…
-
V31 over 7 years@mBlaze: Just wondering if you were able to resolve your issue. If yes then please mark the answer accepted.
-
Somename about 7 yearsWhy aren't there a million likes for this answer? This helped me. Thanks. You may want to update :
aws.config.update({ signatureVersion: 'v4',
as I was getting an error and doing this solved it. -
Nilesh Modak over 6 yearsReally helpful.
-
Mobasher Fasihy about 5 yearsfor me the same line of codes shows this error
"error":{"errno":-4058,"syscall":"open","code":"ENOENT","path":"undefined/undefined"}
-
Pulkit Aggarwal almost 5 yearsHow we can get the s3 url where we upload the file.
-
Satyam almost 5 yearsCan you please post the details of the request and body that has to be called from Angular front end or from postman client?
-
Anjum.... almost 5 years@Satyam Please check attachment screenshot for post body in Postman
-
Anns Rahim over 4 yearsI tried this code and i got a error like "Error: Unexpected end of multipart data" i dont know why i was searching for solution for couple of days please help me
-
Aimery over 4 yearsWelcome to SO :) Please edit your answer to explain how your code solves the problem OP is facing.
-
Zeeshan Hassan Memon over 4 yearsnext edit may be :) @Anjum.... has answered very well still I want to add my 2 cents.
-
Angelzzz about 4 yearsThanks. It works to download file, but when I try to use thi link, it show access denied. How to handle this?
-
Zeeshan Hassan Memon about 4 years@Angelzzz pass
acl: 'public-read'
abovebucket: 'bucket-name'
to get desired results. -
kd12345 over 3 yearsHi, can you please have a look at my question here, would really appreciate the help.stackoverflow.com/questions/65479245/nodejs-multer-aws-s3
-
kd12345 over 3 years@ZeeshanHassanMemon Hi, hope you are good. Can you please have a look at my question would really appreciate the help. stackoverflow.com/questions/65479245/nodejs-multer-aws-s3
-
Tyler Chong about 3 yearsIt should be in res.files.location @PulkitAggarwal
-
Pedro Contipelli over 2 yearsThe file URL will be in req.file.location
-
murage kibicho about 2 years2022 update : This solution does not work anymore
-
kd12345 about 2 yearshi can you please have a look at my question. stackoverflow.com/questions/71724311/nodejs-multer-s3-sequelize
-
kd12345 about 2 yearshi can you please have alook at my question stackoverflow.com/questions/71724311/nodejs-multer-s3-sequelize
-
kd12345 about 2 yearshi can you please have a look at my question stackoverflow.com/questions/71724311/nodejs-multer-s3-sequelize
-
Zeeshan Hassan Memon about 2 yearsMarch 2022 update: It works perfectly fine, just tested it myself. @muragekibicho how can I help you?
-
murage kibicho about 2 yearsNo offence, it does not work - that's why I said it does not work. It may work on your device because of the library versions you are using. @ZeeshanHassanMemon You can help me by letting people know this solution does not work in 2022
-
Zeeshan Hassan Memon about 2 yearsAt least tell me the issue so that I can understand what are you facing actually :) or visit the link: github.com/zishon89us/node-cheat/tree/master/aws/… to know the proper package versions.