I am build a web app with Node.js and React and I am trying to store some files at my backend.
For some reason i cant access to my req.path , although I configured all multer strategies.
const multer = require('multer')
const config = require('config')
const auth = require('../../middleware/auth')
const {check , validationResult } = require('express-validator');
const storage = multer.diskStorage({
destination: function(req, file , cb){
cb(null,'uploads/')
},
filename: function(req, file, cb){
cb(null, req.user.id)
}
});
const fileFilter = (req, file , cb) =>{
if(file.mimetype === 'image/jpeg' || file.mimetype === 'image/jpg' || file.mimetype === 'image/png')
cb(null,false);
else
cb(null,true);
}
my route:
router.post('/' , [auth,upload.single('image'),
[
check('status','Status is required').not().isEmpty(),
check('skills','Skills is required').not().isEmpty(),
check('gender','Gender is required').not().isEmpty()
]],
async (req,res) => {// cant access to req.file.....}
and my react form:
<div className="form-group">
<input type="text" placeholder="Choose profile image" name="profileImage" value={image}/>
<input type="file" placeholder="Upload" enctype="multipart/form-data" name="image" onChange={(e) => onChange(e)}/>
<small className="form-text">The image must not be bigger then 5MB and only JPG\JPEG\PNG types</small>
</div>
Please , what am i doing wrong?
I have used multer in my backend application and this is how I have configured it and it works properly and stores required files in server file directory.
First, installing multer
npm i multer --save
Second, initialize it at the top of required .js file
const multer = require("multer");
Now, configuring storage (storage location and filename)
const storage = multer.diskStorage({
destination: "./public/uploads/postimages/",
filename: function (req, file, cb) {
cb(
null,
file.fieldname + "-" + Date.now() + path.extname(file.originalname)
);
},
});
Init multer function, (configure own file size)
Use array if you want to upload multiple files at once, 10 is the number of files, you can modify it as needed.
const upload = multer({
storage: storage,
limits: { fileSize: 10000000000 },
}).array("image", 10);
// Use .single("image"); if you want to upload a single file.
// image is the name/key that is sent from frontend with the file(s).
If you are using array, you can create an api that stores file, which will look like this.
try {
let imagePath = "abc";
let postId = req.params.postId;
let imagesLinks = [];
await upload(req, res, (err) => {
if (err) {
console.log(err);
} else {
if (req.files == undefined) {
console.log("File not found.");
} else {
//image uploaded successfully
req.files.map(function (file) {
imagePath = "uploads/postimages/" + file.filename;
imagesLinks.push(tmp);
});
}
}
res.status(201).send(imagesLinks);
});
}
For a single file, it looks as simple as this
try {
let imagePath = "abc";
upload(req, res, (err) => {
if (err) {
res.status(300).send(err);
console.log(err);
} else {
if (req.file == undefined) {
res.status(301).send("image upload failed.");
} else {
//image uploaded successfully
imagePath = "uploads/" + req.file.filename;
storeImageLink(res, imagePath);
}
}
});
}
Look at these examples. They will be help you:
File Upload With Multer in Node.js and Express
Multer Storage:
// SET STORAGE
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'uploads')
},
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now())
}
})
var upload = multer({ storage: storage })
Handling File Uploads:
app.post('/uploadfile', upload.single('myFile'), (req, res, next) => {
const file = req.file
if (!file) {
const error = new Error('Please upload a file')
error.httpStatusCode = 400
return next(error)
}
res.send(file)
})
Reactjs nodejs upload image — How to upload image using reactjs and nodejs (multer)
Node.js:
const path = require("path");
const multer = require("multer");
const storage = multer.diskStorage({
destination: "./public/uploads/",
filename: function(req, file, cb){
cb(null,"IMAGE-" + Date.now() + path.extname(file.originalname));
}
});
const upload = multer({
storage: storage,
limits:{fileSize: 1000000},
}).single("myImage");
const router = express.Router();
router.post("/upload", {
upload(req, res, (err) => {
console.log("Request ---", req.body);
console.log("Request file ---", req.file);//Here you get file.
/*Now do where ever you want to do*/
if(!err)
return res.send(200).end();
});
};);
This is my File Upload.js but when i upload file it will get uploaded succesfully but its extension is missing i want to upload file with extension .Please help me
const aws = require('aws-sdk');
const multer = require('multer');
const multerS3 = require('multer-s3');
aws.config.update({
secretAccessKey: '',
accessKeyId: '',
region: 'us-east-2'
});
const s3 = new aws.S3({ })
const fileFilter = (req, file, cb) => {
if (file.mimetype === 'music/AAC' || file.mimetype === 'music/AVI' ||file.mimetype === 'music/mp3' ||file.mimetype === 'music/AVI') {
cb(null, true)
} else {
cb(new Error('Invalid Mime Type, only JPEG and PNG'), false);
}
}
const upload = multer({
storage: multerS3({
fileFilter,
s3,
bucket: 'admin-song',
acl: 'public-read',
metadata: function (req, file, cb) {
cb(null, {fieldName: 'TESTING_META_DATA!'});
},
key: function (req, file, cb) {
cb(null, Date.now().toString())
}
})
})
module.exports = upload;
And This is my Api End Point Guide Me Please
app.post('/v1/admin/upload/song',function(req, res) {
singleUpload(req, res, function(err) {
if (err) {
return res.status(422).send({errors: [{title: 'File Upload Error', detail: err.message}] });
}
console.log(res)
return res.json({'imageUrl': req['file'].location});
});
});
You have to add whatever string you want as filename in your multer function.You can add file extension to the file with the following method
const upload = multer({
storage: multerS3({
fileFilter,
s3,
bucket: 'admin-song',
acl: 'public-read',
metadata: function (req, file, cb) {
cb(null, {fieldName: 'TESTING_META_DATA!'});
},
key: function (req, file, cb) {
cb(null, Date.now().toString() + '.' + fileExtension)
}
})
})
I am using multer-s3 to upload files to was S3. When i upload a file it all works fine and I have never had an error, however most tutorials do not mention anything about how to handle a case where there may be an issue with uploading files.
My upload is as follows
var upload = multer({
storage: multerS3({
s3: s3,
bucket: 'my bucket',
key: function (req, file, cb) {
console.log(file);
cb(null, file.originalname);
}
})
});
And i call it from the
app.post('/File/Add' , storage_functions.upload.single('file'), function (req, res) {
console.log('file uploaded')
});
does multers3 provide some kind of response on upload. This would be useful to access errors but would also be useful if the response contained the file path in s3.
You can add callback function to handle errors.
const upload = storage_functions.upload.single('file');
app.post('/File/Add', function (req, res) {
upload(req, res, function (err) {
if (err) {
// your error handling goes here
}
});
});
To find more details, multer documentation
This is what i did for handling errors:
I have created a file s3.js, which includes multer-s3 configuration and error handler
import S3 from 'aws-sdk/clients/s3.js'
import multer from 'multer'
import multerS3 from 'multer-s3'
import dotenv from 'dotenv'
dotenv.config()
const region = process.env.S3_REGION
const s3 = new S3({
region
})
// upload to S3 storage
export const uploadFiles = (req, res, next) => {
const upload = multer({
limits: { files: 6 },
storage: multerS3({
s3: s3,
bucket: process.env.S3_BUCKET_NAME,
metadata: function(req, file, cb) {
cb(null, { fieldName: file.fieldname })
},
key: function(req, file, cb) {
cb(null, `images/users/${ req.userId }/products/${ req.body.name }/${ new Date().toISOString() }-${ file.originalname }`)
},
})
}).array('photos', 6)
// Custom error handling for multer
upload(req, res, (error) => {
if (error instanceof multer.MulterError)
return res.status(400).json({
message: 'Upload unsuccessful',
errorMessage: error.message,
errorCode: error.code
})
if (error)
return res.status(500).json({
message: 'Error occured',
errorMessage: error.message
})
console.log('Upload successful.')
next()
})
}
You can now use this on the route that you want to upload files to.
import express from 'express'
import { uploadFiles } from '../config/s3.js'
const router = express.Router()
router.post('/upload', uploadFiles, async(req, res) => {
console.log(req.files)
})
export default router
Because I set the file limit to 6 I will get the following response when I try to send more than 6 files.
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?
[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!
#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
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);
});
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())
}
})
})
MulterS3 Docs
/*** Using Multer To Upload Image image is uploading */
const fileStorage = multer.diskStorage({
destination: function(req, file, cb) {
cb(null, "./public/uploads");
},
filename: function(req, file, cb) {
cb(null, file.originalname);
}
});
/** AWS catalog */
aws.config.update({
secretAccessKey: process.env.SECRET_KEY,
accessKeyId: process.env.ACCESS_KEY,
region: "us-east-1"
});
const s3 = new aws.S3();
const awsStorage = multerS3({
s3: s3,
bucket: process.env.BUCKET_NAME,
key: function(req, file, cb) {
console.log(file);
cb(null, file.originalname);
}
});
const upload = multer({
storage: awsStorage(),
/** in above line if you are using local storage in ./public/uploads folder than use
******* storage: fileStorage,
* if you are using aws s3 bucket storage than use
******* storage: awsStorage(),
*/
limits: { fileSize: 5000000 },
fileFilter: function(req, file, cb) {
checkFileType(file, cb);
}
});
app.post("/user-profile-image", upload.single("profile"), (req, res, err) => {
try {
res.send(req.file);
} catch (err) {
res.send(400);
}
});
const checkFileType = (file, cb) => {
const filetypes = /jpeg|jpg|png|gif/;
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: Images Only!");
}
};
//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);
I was passing S3 to mutler in caps, like
S3: {object}
Changing it to small s3 works for me:-
s3: {object}
WE can Upload IMAGE/ CSV/ EXCEL files to AWS s3 using multer-s3.
Im using .single(fieldname) method for uploading single file.
const aws = require('aws-sdk');
const multer = require('multer');
const multerS3 = require('multer-s3');
const s3 = new aws.S3({
accessKeyId: process.env.AWS_ACCESS_KEY,
secretAccessKey: process.env.AWS_SECRET_KEY,
region: process.env.REGION,
});
const upload = multer({
storage: multerS3({
s3: s3,
bucket: process.env.AWS_S3_BUCKET,
metadata: function (req, file, cb) {
cb(null, {fieldName: 'Meta_Data'});
},
key: function (req, file, cb) {
cb(null, file.originalname);
},
limits: {
fileSize: 1024 * 1024 * 5 // allowed only 5 MB files
}
})
}).single('file');
exports.uploadfile = async(req,res,next)=>{
try{
upload(req,res, function(err){
if(err){
console.log(err);
}
console.log(req.file.location);
})
})
}catch (err){
res.status(400).json({
status : 'fail',
message : err.message
});
}
}
In Routes file
router.route('/')
.post(imageController.uploadfile);