(Self Q&A) HOW TO SETUP AND USE the MULTER MIDDLEWARE) for single file upload ( Expressjs/Nodejs ) - node.js

Just wanted to post an answer to a beginner level question on HOW TO SETUP AND USE the MULTER MIDDLEWARE in Expressjs/Nodejs

Hope this saves your time
There should be two files:
1.Jade file(which shall contain the form lets assume index.jade)
2.JS file(which is located in the routes folder, and which directs to the index.jade file in the views folder)
SETUP index.jade file
//not a jade file so convert it to jade
//enctype is set to multipart/form-data --- multer requirement
<form method="post" role="form" enctype="multipart/form-data">
<div class="form-group">
<label for="upload">Email address:</label>
//name attribute to access in index.js route file
<input type="file" class="form-control" name="upload" id="upload">
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
//very important
(a)In the Jade file the form must contain the attribute of enctype = "multipart/form-data"
(b)Input should have a name attribute which gets accessed in the index.js file
SETUP JS ROUTE FILE(index.js) not in app.js
var express = require('express')
var multer = require('multer')
var upload = multer({ dest: 'uploads/' }) //set dest to where you want to upload the file
var app = express()
// SINGLE FILE UPLOAD
app.post('/', upload.single('upload'), function (req, res, next) {
//since we are performing a single file upload req.file will be used and not req.files
// req.file would attach the file with upload fieldname ~ upload is the name attribute given in the form
//now use req.file to access the file
//for example
console.log(req.file); // this would display the file attributes in the log
})

Related

Why React doesn't upload image to server?

I have an app using react and express on the backend and multer to manage the upload. The server side is running properly when I make tests using postman, but if trait to send an image from react the result is unexpected. In that case the file doesn't appear in the uploads folder, however with postman is immediatly.
UploadPage,jsx
const { register, handleSubmit } = useForm();
const onSubmit = async (data) => {
const formData = new FormData();
formData.append('petimage', data.petimage);
try {
const res = await axios.post('/api/petregister', formData);
console.log(res)
} catch (error) {
setError(error.response.data.error);
setTimeout(() => {
setError("");
}, 5000);
}
}
return (
<Container className="mt-5">
<Form onSubmit={handleSubmit(onSubmit)}>
<Form.Group controlId="formFile" className="mb-3">
<Form.Label>Imagen de tu Mascota</Form.Label>
<Form.Control type="file"
label="Select image"
name="petimage"
{...register("petimage")}
/>
</Form.Group>
<Button variant="primary" type="submit">
Submit
</Button>
</Form>
</Container>
Google Response
The fields with name petimage are the same that I expecified in the backend and used these in the postman tests.
Edit
const store = require('../middlewares/multer');
route.post('/petregister', store.array('petimage', 12), petregister);
The last section of code is the route that is linked with the multer midleware asigned to ssave the images.
When you are making a API call to the backend, it will upload the image to the specific folder that you are defining in the backend like :
const multer = require('multer');
const upload = multer({ dest: 'folder path' });
I think you are getting results unexpected because the name for the image you are giving in formData formData.append('petimage', data.petimage); i.e petimage, it should be the same in the multer fileupload method. You haven't shared the backend code. So, I'm hoping that it may be like this:
var fileUpload = upload.single('petimage'); when the name is the same it will work fine.
If the image is of big size, you can compress it. Please visit this link, it will help you for sure.
https://dev.to/franciscomendes10866/image-compression-with-node-js-4d7h
You can try:
Remove
formData.append('petimage', data.petimage);
and use instead
data.petimage.forEach(pet => formData.append("petimage", pet))
The solution was trait the image as an object. The code is the next:
Object.values(data.petimage).forEach(pet => formData.append('petimage', pet))
Then it worked as expected.

Extracting uploaded csv data with multer

I am porting a rails app over to use the MEEN stack (Mongo, Express, Ember, Node)
I have a function that takes an uploaded csv and extracts the data from it and uses the data to then form SQL queries to a database. For some reason I am having issues with accessing the uploaded csv data with multer.
My Router file
var quotes = require('../api/quote');
var cors = require('cors');
var sku = require('../api/tools/sku');
var multer = require('multer');
var upload = multer({ dest: 'uploads/' });
var util = require("util");
var fs = require("fs");
var corsOptions = {
origin: 'http://localhost:4200'
}
module.exports = function(router){
router.route('/quotes').post(cors(corsOptions),function(req,res){
console.log(req.body);
quotes.addQuote(req,res);
}).get(cors(corsOptions),function(req,res){
quotes.getAllQuotes(req,res);
});
router.route('*').get(cors(corsOptions), function(req,res){
res.sendFile('public/index.html',{root:'./'});
});
router.post('/tools/sku/reactivate',upload.single('csvdata'),function(req,res){
console.log(req.files);
console.log('handing request over to sku.reactivate');
sku.reactivate(req,res);
});
};
My handlebars file for the tools/sku/reactivate template
<div class="col-md-8 col-md-offset-2 text-center">
<h2 class="toolTitle">Reactivate SKUs</h2>
<p class="lead">CSV Should Contain 1 Column (SKU) Only</p>
{{file-upload enctype="multipart/form-data" type="file" url="/tools/sku/reactivate" class="center-block" accept="text/csv" name="csvdata"}}
</div>
i am getting Error: Unexpected field when I attempt to post the file upload to the /tools/sku/reactivate post route. I don't understand whats wrong with my code.
The issue was using the file-upload ember addon. As soon as I removed the handlebars component and just hardcoded a form as seen below, the file upload's successfully.
<div class="col-md-8 col-md-offset-2 text-center">
<h2 class="toolTitle">Reactivate SKUs</h2>
<p class="lead">CSV Should Contain 1 Column (SKU) Only</p>
<form action="/tools/sku/reactivate" method="POST" enctype="multipart/form-data">
<input class="center-block" type="file" name="csvdata">
<button type="submit" class="btn btn-md btn-danger">Submit</button>
</form>
</div>

Req.file object is always undefined, HTTP file upload

I'm trying to upload a file in meteor using HTTP POST method and enctype="multipart/form-data"
WebApp.connectHandlers.use("/api/v1/upload", function(req, res, next) {
console.log(req.files); //undefined
console.log(req.file); //undefined
console.log(req);
})
I tried with WebApp but getting undefined file property under request object
I also tried with multer and Picker but no luck.
const _multerInstanceConfig = { dest: '/tmp' }; // Temp dir for multer
const _multerInstance = multer(_multerInstanceConfig);
Picker.middleware(_multerInstance.single('photo'));
Picker.route('/api/v1/upload', function(params, req, res, next) {
console.log(req.files); //undefined
console.log(req.file); //undefined
console.log(req);
})
This is simplest form I'm trying to upload is
<form action="http://localhost:3000/api/v1/upload" method="POST" enctype="multipart/form-data">
<input type="file" name="file" />
<input type="submit" value="Upload File" />
</form>
Am I missing something here? not sure.
Also, I don't want to upload files using base64 data string via DDP as it very slow.
I've check couple of link also with no luck
multer - req.file always undefined
https://github.com/noris666/Meteor-Files-POST-Example
PS: I need to upload images via native Android/iOS clients.
Thanks, everyone, who has spent their time on my question, I got the solution for the problem from git issue, I raised.
I'm posting here my solution if someone else also faces the similar problem.
It was because of the name of this input field
<input type="file" name="file" />
which doesn't match with
Picker.middleware(_multerInstance.single('photo'));
changing either of them to will make it work perfectly.

Formidable upload file don't trigger

Development and test environment:
Windows 8 64bit
node version installed 0.10.5
npm version 1.2.18
express framework
formidable module used for file uploading
Firefox and Internet Explorer browsers
HTML code:
<form id="caricaMasterImg" method="post" enctype="multipart/form-data" action="/image/upload">
<input type="file" id="masterImg" name="masterImg" value="Sfoglia" accept="image/*"/>
<input type="submit" value="carica" id="submitLoadImg" />
</form>
app.js code:
var image = require('./route/image');
app.post('/image/upload', image.upload);
routes/image.js code:
exports.upload = function(req, res){
var form = new formidable.IncomingForm();
form.uploadDir = path.join(__dirname, 'tmp');
console.log('Upload directory is: '+form.uploadDir);
fs.exists(form.uploadDir, function (exists) {
console.log('is an existing directory? '+exists);
});
form.parse(req, function(err, fields, files) {
console.log(fields);
console.log(files);
});
};
The issue:
When submit button is clicked I expect to see the file logged with console.log(files) instruction. Log writes:
Upload directory is: C:\Liber-I\app\FileSystemManager\routes\tmp
is an existing directory? true
No more log is written on application console for several minutes.
I test the case of no-file submission and it seems it is acting the same! It is a too weired behaviour to be a nodejs problem, where am I doing wrong?
I think I did nothing wrong. Truth is I am not able to fix this problem, so I decided for a good work around. I choose to use connect-multiparty for file uploading and it is working just great.

Accessing Upload Image in Server Side

I am supposed to upload image & store it in GridFS. My problem here is I am not getting selected image by user on server side.
<input type="file" name="letterhead" />
Server Side
console.log(req.files);
It shows me undefined.
I see you tagged it as AngularJS so I assume you use the file input inside AngularJS controller. As far as I'm aware ngModel doesn't work on file inputs. I personally do it this way
<input type="file" id="uploadImage" name="uploadImage" onchange="angular.element(this).scope().setFiles(this)">
and then in controller
$scope.setFiles = function (element) {
$scope.$apply(function () {
$scope.file = element.files[0];
//from now on you can do whatever you want with your image $scope.file
});
};

Resources