how to read posted data on node js api - node.js

i want to read the csv data uploaded to backened.
for this i am sending the data via post from front end..
frontend code:
fileEvent(e) {
this.filedata = e.target.files;
if (this.filedata.length > 0) {
const file: File = this.filedata[0];
console.log(file);
const formData: FormData = new FormData();
formData.append('files', file, file.name);
this.http.post('myUrl', {file: formData}, this.options)
.subscribe((res) => {
});
}
}
screenshot of my file:
now on backened i have written route on api.js that directs me
to the controller i have created.
my api.js code:
router.post('/product/csvdata', function (req, res) {
productimport.importcsvProduct(req, res);
});
and finally on my controller i am consoling my data:
var product = {
importcsvProduct: function (req,res) {
console.log(req.body.file);
}
};
module.exports = product;
but i am getting empty {} in console..??
can anyone check whats wrong with this..??

You need to use a file handling middleware in this case, such as multer.
const express = require('express')
const multer = require('multer')
const upload = multer({ dest: 'uploads/' })
const app = express()
app.post('/profile', upload.single('csvdata'), function (req, res, next) {
// req.file is the `csvdata` file
// req.body will hold the text fields, if there were any
})

Related

getting filename of formdata after axios request

I have a quick question. I would like to extract the file name of a wav file I am passing to my backend through axios using formData. I am not sure how to do this is nodejs. I would appreciate any help
Frontend:
//file is a Blob
var new_file = new File([file], bucket_string);
var formData = new FormData();
formData.append("wavfile", new_file, bucket_string);
const config = {
headers: { 'content-type': 'multipart/form-data' }
}
return await axios.post(`/files/upload-file`, formData, config);
//return await axios.post(`http://localhost:2000/files/upload-file`, data);
backend:
controller.js
async function uploadFile(req, res, next) {
fileService.uploadFile().then(function(val) {
res.json(val)
});
} 
service.js
function uploadFile({ data }) {
const file = data;
var file_name = ?
//i would like to get the file name here
}
const express = require('express');
const multer = require('multer');
const app = express();
const upload = multer();
function uploadFile(req, res, next) {
console.log(req.file.originalname);
res.json({ok: true}).end();
}
app.post('/', upload.single('wavfile'), uploadFile);
app.listen(3001);

Unable to upload images with multer

I'm trying to upload images. It's reaching the backend, but the request body and req.image are coming out empty.
I have the submission:
const handleSubmit = async () => {
try {
const data = createFormData();
console.log(data); // prints the correct request object
const response = await axios.post(
`http://${GATEWAY}:5000/api/uploads/single`,
JSON.stringify(data)
);
alert("Upload success!");
console.log("response.data", response.data);
} catch (err) {
console.log("err caught --> ", err);
}
};
const createFormData = () => {
const data = new FormData();
data.append("title", title); // coming from
data.append("body", body); // react hooks state (useState)
data.append("image", {
height: image.height,
width: image.width,
type: image.type,
uri:
Platform.OS === "android" ? image.uri : image.uri.replace("file:/", "")
});
return data;
};
My endpoint:
const express = require("express");
const multer = require("multer");
const bodyParser = require("body-parser");
express().use(bodyParser.json());
const router = express.Router();
// middleware
const auth = require("../../middleware/auth");
const storage = multer.diskStorage({
destination(req, file, callback) {
callback(null, "./images");
},
filename(req, file, callback) {
callback(null, `${file.fieldname}_${Date.now()}_${file.originalname}`);
}
});
const upload = multer({ storage });
// #route POST api/uploads/single
// #desc Upload single image
// #access Private
router.post(
"/single",
// upload.array("photo", 3),
auth,
upload.single("image"),
(req, res) => {
console.log("req", req.body); // {}
console.log("req", req.image); // undefined
return res.status(200).json({
message: "Response from backend"
});
}
);
module.exports = router;
And my server.js
const express = require("express");
const connectDb = require("./config/db");
const app = express();
// connect to db
connectDb();
// Define routes (some omitted for brevity)
app.use("/api/uploads", require("./routes/api/uploads"));
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`Listening on port ${PORT}`));
For some reason, in the first snippet, if I do not stringify the data: FormData object that is built from createFormData(), my backend is never even reached.
I've tried so many things, and I'm not starting to think that maybe my backend isn't setup properly. The line where I'm doing express().use(bodyParser.json()); exists because I can't do app.use(bodyParser.json()); (or at least I think), because the app object is in the main server.js file. I'm including other API routes in other files.
For example, my server.js has these, amongst others:
// Define routes
app.use("/api/auth", require("./routes/api/auth"));
app.use("/api/users", require("./routes/api/users"));
app.use("/api/profile", require("./routes/api/profile"));
app.use("/api/uploads", require("./routes/api/uploads"));
And I was following this tutorial to use multer with react-native. A little lost at this point, not sure what I'm doing wrong.
Edit:
I'm making the request like this now,
const config = {
headers: {
"Content-Type": "multipart/form-data"
}
};
const response = await axios.post(
`http://${GATEWAY}:5000/api/uploads/single`,
data,
config
);
But It's failing with a
If I stringify it, it hits the backend but not in the way I need it to:
Edit:
I got it working by specifying the image type, as per the suggestion here
I think this is because you are not setting your content-type to multipart/form-data. Try adding this to your request options:
const response = await axios.post(
`http://${GATEWAY}:5000/api/uploads/single`,
data,
headers: {
`Content-Type`: `multipart/form-data`
}
);
Because of multipart/form-data, do not stringify the data you are sending. Stringifying the data will cause it to only be read as text by the server but is expecting a file to be attached.
Got it working by specifying the image type as per the suggestion here
You're trying to access the file from req.image and req.body, but as mentioned in the https://www.npmjs.com/package/multer, you can access it from :
req.file
req.body will hold the text fields only, on the other hand, if you only uploaded a single file you can find it in req.file, but if you uploaded multiple files you will find them in req.files.
I used the following line to get images:-
concole.log(req.files);

Can't upload file using express-fileupload

I'm using express-fileupload module to parse uploaded file.
Upload is done with axios.
const formData = new FormData();
formData.append("file", data.gameCover);
formData.append("gameTitle", data.gameTitle);
formData.append("gamePrice", data.gamePrice);
formData.append("description", data.description);
return axios.post(apiUrl + "/games/add", formData).then(res => {
dispatch({ type: ADD_GAME, payload: res.data.game });
});
This is the POST request
Serverside code looks like this:
router.use(fileUpload());
router.post("/add", (req, res) => {
if (!req.files) return res.status(400).send("No files were uploaded.");
Of course I'm getting "No files were uploaded" when trying to upload.
Finally after debugging step after step found that data.gameCover is an array
so that's the solution
formData.append("file", data.gameCover[0]);
You can optionaly use multer for handling multipart/formdata.
you can then get the uploaded file as follows
const express = require('express');
const path = require('path');
const router = express.Router();
const multer = require('multer');
const storage = multer.diskStorage(
{destination: (req, file, cb)=>{
cb(null, path.join(__dirname, '../uploads'));
},
filename: (req, file, cb)=>{
cb(null, file.originalname);
}
});
let upload = multer({storage: storage});
// access the uploaded file with your route handler
router.post('/upload',upload.single('file'), (req, res, next)=> {
if(req.file){
//you can access your uploaded file
}
});

Sending file from one node js server to another

So on first server I have route like this:
const express = require('express');
const router = express.Router();
const FormData = require('form-data');
const fetch = require('node-fetch');
const multer = require('multer');
const storage = multer.memoryStorage();
const upload = multer({ storage });
router.post('/', upload.single('file'), async (req, res) => {
const form = new FormData();
form.append('folderId', req.body.folderId);
form.append('file', req.file.buffer, req.file.filename);
const result = await fetch('http://localhost:3003/users', { method: 'POST', body: form }).then(res => res.json());
res.json(result);
})
On this server, it works fine, I can see req.file and it's buffer. So I wanna send this file (without storing it on first server, it exists only in memory and as buffer) to another.
Other server route is like this:
const express = require('express');
const router = express.Router();
const multer = require('multer');
const path = require('path');
const putanja = path.join(__dirname, '../uploads/users');
const storage = multer.diskStorage({
destination: (req, file, cb) => {
console.log('entered here?')
if (!req.body.folderId) return cb({ message: 'no folderId' });
if (!fs.existsSync(putanja + '/' + folderId)) fs.mkdirSync(putanja + '/' + folderId);
cb(null, putanja + '/' + folderId);
},
filename: (req, file, cb) => cb(null, file.originalname)
});
const upload = multer({ storage });
const fs = require('fs');
router.post('/', upload.single('file'), async (req, res) => {
console.log(req.body)
console.log(req.file)
res.json({ status: 'ok' })
})
So on second server, it doesn't even enter the multer middleware, req.file is always defined, and that console.log('entered here?') is never seen. Looks like I'm not passing data as multipart-form?
Also, second server, when sending file directly to it via postman, works.
So my question, how do I send that file? As a buffer? Stream? Base64? I think I tried everything, even changed node-fetch to request, but still no luck.
So on second server, it doesn't even enter the multer middleware, req.file is always defined, and that console.log('entered here?') is never seen. Looks like I'm not passing data as multipart-form?
So this mean your second server doesn't understand the Content-Type of request.
So do one thing add Content-Type parameter in header when you are sending request to second server
Add Content-Type to multipart/form-data
or if you don't know pass headers : {
'Content-Type' : undefined
} http will set header for you
You send your request to /users (http://localhost:3003/users) yet your second server expects the request on /.
Try changing either one to match the other.
'use strict';
const express = require('express');
const multer= require('multer');
const concat = require('concat-stream');
const request = require('request');
const router = express.Router();
function HttpRelay (opts) {}
HttpRelay.prototype._handleFile = function _handleFile (req, file, cb) {
console.log('hell0 proto');
file.stream.pipe(concat({ encoding: 'buffer' }, function (data) {
const r = request.post('/Endpoint you want to upload file', function (err, resp, body) {
if (err) return cb(err);
req.relayresponse=body;
cb(null, {});
});
const form = r.form();
form.append('uploaded_file', data, {
filename: file.originalname,
contentType: file.mimetype
});
}))
};
HttpRelay.prototype._removeFile = function _removeFile (req, file, cb) {
console.log('hello');
cb(null);
};
const relayUpload = multer({ storage: new HttpRelay() }).any();
router.post('/uploadMsgFile', function(req, res) {
relayUpload(req, res, function(err) {
res.send(req.relayresponse);
});
});
module.exports = router;

How to mock multer with supertest?

I'm writing file upload API and have some troubles with mocking multer. I'm trying to test my endpoint with supertest.
it('load image', async () => {
await app
.post(`${apiImage}`)
.set('Authorization', 'abc123')
.attach('avatar', `${__dirname}/test.jpg`);
.expect(200);
});
Upload works as expected. But every time when I run test, new file being created. So, how to mock multer and does not create new file every time?
I had a middleware helper to wrap multer like this
// middleware/index.js
const multer = require('multer');
exports.multerUpload = () => multer({...});
Then use it in my routes like so
// routes.js
const { multerUpload } = require('path/to/middlewares');
app.post('/upload', multerUpload().any());
Then, in my tests, I can stub out multerUpload
// test.js
const middlewares = require('path/to/middlewares');
sinon.stub(middlewares, 'multerUpload').callsFake(
() => {
return {
any() {
return (req, res, next) => {
// You can do whatever you like to the request body here e.g
req.body = { title: req.query.title };
req.files = [{ location: 'sample.url', key: 'sample.key' }];
return next();
};
},
};
},
);
Mock Multer using Jest (Similar to above ans but using Jest)
App.js
Used multer as middleware
const app = express();
app.use()
app.use(multer({ dest: FILE_UPLOAD_PATH }).single('datafile'));
app.use('/api', apiRoutes);
apiRoute.js
router.post('/datasources', async function (req, res) {
...
});
apiRoute.test.js
const multer = require('multer');
jest.mock('multer');
multer.mockImplementation(() => {
return {
single() {
return (req, res, next) => {
req.body = { title: req.query.title };
req.file = [{ originalname: 'sample.name', mimetype: 'sample.type', path: 'sample.url' }];
return next();
};
},
};
});
.
.
.

Resources