I am using multer to upload images to my cloudinary account. Since the images will be uploaded to cloud I do not need them to be stored locally in my app. I am using the MemoryStorage option as given in the documentation.
var cloudinary = require('cloudinary');
var multer = require('multer');
var storage = multer.memoryStorage();
var upload = multer({ storage: storage });
var cloudinaryConfig = require('../config/cloudinary');
router.post('/', upload.single('image'), function(req, res){
cloudinary.config(cloudinaryConfig.connection);
cloudinary.uploader.upload(req.file.path,{tags:'basic_sample'},function(err,image){
if(err){
console.warn('------------------- ERROR: ' + err);
}
console.log("* public_id for the uploaded image is generated by Cloudinary's service.");
console.log("* "+image.public_id);
console.log("* "+image.url);
});
});
However while uploading the image is also uploaded to an "uploads" folder. Any idea what the problem is? Thank you.
Any progress on this one? Or is it me doing something wrong?
Sorry for the delay on this, I think what's happening is that you already have another multer middleware running before the upload.single('image') one. The memory storage doesn't provide a req.file.path property, but instead gives you a buffer at req.file.buffer.
Can you show how the router object is being used?
The following small example works for me:
const express = require('express')
const multer = require('multer')
const app = express()
const storage = multer.memoryStorage()
const upload = multer({ storage })
app.post('/', upload.single('image'), (req, res) => {
console.log('Should be undefined:', req.file.path)
console.log('Should be the buffer:', req.file.buffer)
res.send('OK')
})
app.get('/', (req, res) => {
res.type('text/html').send(`
<html>
<head>
<title>Test upload</title>
</head>
<body>
<form method="post" enctype="multipart/form-data">
<input type="file" name="image" />
<input type="submit" />
</form>
</body>
</html>
`)
})
app.listen(3000, () => console.log('http://localhost:3000/'))
In app.js
var profile = require('./routes/profile');
app.use('/profile', profile);
So in profile.js
var express = require('express');
var router = express.Router();
var cloudinary = require('cloudinary');
var multer = require('multer');
var storage = multer.memoryStorage();
var upload = multer({ storage: storage });
var cloudinaryConfig = require('../config/cloudinary');
router.get('/, function(req, res){
res.render('profile');
});
router.post('/', upload.single('image'), function(req, res){
cloudinary.config(cloudinaryConfig.connection);
cloudinary.uploader.upload(req.file.path,{tags:'basic_sample'},function(err,image){
if(err){
console.warn('------------------- ERROR: ' + err);
}
console.log("* public_id for the uploaded image is generated by Cloudinary's service.");
console.log("* "+image.public_id);
console.log("* "+image.url);
});
});
module.exports = router;
This is how router is used.
Could you elaborate on app.js? It seems like the only possibility is that multer is called on app somewhere, before the profile router is even hit...
I am putting my app.js code here. I am not using multer in app.js since profile is the only page where multer is being used right now for uploading images.
var express = require('express'); //create a new express app
var exphbs = require('express-handlebars');
var router = express.Router(); //use express 4.0 router to define routes
var bodyParser = require('body-parser'); //pull information from html post
var methodOverride = require('method-override'); //perform put and delete request
var favicon = require('serve-favicon'); //favicon middleware
var http = require('http');
var path = require('path');
var mysql = require('mysql');
var cookieParser = require('cookie-parser');
var session = require('express-session');
var passport = require('passport');
var profiles = require('./routes/profiles');
var app = express(); //create our app with express
require('./config/passport')(passport);
app.engine('handlebars', exphbs({defaultLayout: 'main'})); //set the app engine and default layout name 'main'
//configuration for express
//app.set
app.set('port', process.env.PORT || 8000); //set port to either environment port OR 8000
app.set('views', path.join(__dirname, 'views')); //by default, express expects its template files to be in the views folder. In case you have a different path, you can update it here.
app.set('view engine', 'handlebars'); //define the view engine
//app.use
app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(express.static(path.join(__dirname, 'public'))); //declares the location of static resources (css, js ,images)
app.use(bodyParser.urlencoded({'extended':'true'})); // parse application/x-www-form-urlencoded
app.use(bodyParser.json()); // parse application/json
app.use(bodyParser.json({ type: 'application/vnd.api+json' })); // parse application/vnd.api+json as json
app.use(methodOverride()); //simulate put and delete request
app.use(cookieParser()); // read cookies (needed for auth)
app.use('/profile', profiles);
app.use(function(req, res, next){
var err = new Error('Not Found');
err.status = 404;
next(err);
});
//create server and listen to the port
http.createServer(app).listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
});
module.exports = app;
Any updates on this issue? Is it something from my side?
Same problem, did you solve it?
@enhaster yes, I had to use another node module called fs-extra to come in and empty the uploads directory as soon as the image is uploaded.
var fs = require('fs-extra');
cloudinary.uploader.upload(req.file.path,
function(result){
console.log('-------- public id: ' + result.public_id);
console.log('-------- public url: ' + result.url);
fs.emptyDir('uploads/', function (err) {
if(!err) {
console.log('success! directory empty..');
}
});
},{
folder : '/My IMages/'
}
);
i was able to upload it with memory storage. Cloudinary does not directly upload file buffer, i had to covert the buffer into a datauri.
var Datauri = require('datauri'),
storage = multer.memoryStorage(),
upload = multer({ storage : storage }).single('image');
exports.uploadImage = function (req, res, next) {
upload(req,res,function(err) {
var datauri = new Datauri();
datauri.format('.png', req.file.buffer);
cloudinary.uploader.upload(datauri.content,
function(result) {
if(result.public_id){
//res.sendStatus(200)
}else{
res.sendStatus(500);
}
}
);
});
};
did you solve it?
yes
closing this, thanks for the extra information @abhinav-atmosfi 馃憤
@abhinav-atmosfi hey this was great. Still i have one more quetion. How can i upload multiple files in single call.
@abhinav-atmosfi sweet man. thank you for this! This is what i needed
I was able to do it like this.
let upload = multer({ })
.post('/other', upload.any('image', 10), (req, res, next) => {
const file = req.files[0];
// For documentation refer the following link
// https://cloudinary.com/documentation/node_image_upload
cloudinary.v2.uploader
.upload_stream({ resource_type: 'raw' }, (error, result) => {
console.log(result);
console.log(error);
})
.end(file.buffer);
})
I still have a issue though, once you upload a buffer. You can't get a file extension.
I still have a issue though, once you upload a buffer. You can't get a file extension.
You need to use the datauri package @adeelibr
@ope-oguntoye My approach was to have an upload folder in the end, where I uploaded a particular file on the server. Then once it was saved cloudinary I deleted the file from my own server. I ended up with this approach last year when I was working with multer
@adeelibr There are some instances where you are unable to write to the server's filesystem (ex. Heroku's free tier) in that case memoryStorage is the way to go
Most helpful comment
i was able to upload it with memory storage. Cloudinary does not directly upload file buffer, i had to covert the buffer into a datauri.