How to read file content using nodejs? - javascript

I have file from client that i have to read on server side and send back to client for download , How can i acheive that task using nodejs. I tried with fs but i am getting some error.
console.log(data) is coming as empty object
server.js
var multiparty = require('multiparty');
var data = new multiparty.Form();
export function create(req, res) {
data.parse(req, function(err, fields, files) {
console.log(files);
var fileContent = fs.readFileSync(files.file[0].path,'utf8');
res.json(fileContent );
});
}
router.js
var express = require('express');
var controller = require('./fileUpload.controller');
var router = express.Router();
router.post('/fileUpload',controller.create);
module.exports = router;
fileData
{ file:
[ { fieldName: 'file',
originalFilename: 'sco_poc.bpmn',
path: 'C:\\Users\\9u\\AppData\\Local\\Temp\\f4DG8L7nCpNyNvVPYqGPkd44.bpmn',
headers: [Object],
size: 11078 } ] }

I am assuming you are trying download a local file the path from your JSON object 'fileData'. My example below is written in NodeJS
First, you will need to stringify your JSONobject
var jsonString = JSON.stringify({ file:
[ { fieldName: 'file',
originalFilename: 'sco_poc.bpmn',
path: 'C:\\Users\\9u\\AppData\\Local\\Temp\\f4DG8L7nCpNyNvVPYqGPkd44.bpmn',
headers: [Object],
size: 11078 } ] });
//console.log(jsonString)//print jsonString contents
Second, parse it into a JavaScript object
var jsonObj = JSON.parse(jsonString);
//console.log(jsonObj); //print jsonObj contents
Third, get path from jsonObj
var path = jsonObj.file[0].path;
Finally, read the (local) file
fs.readFile(path,function(err,data){
var fileData="";
fileData+=data;
res.writeHead(200, {
'Location': '<if needed>',
'Content-Type':'<expected content-type>'
});
res.end(fileData); //ends response, and sends to client
});

If you look at the very first example on the multiparty NPM page here: https://www.npmjs.com/package/multiparty, you will see that you need to run this for each new request, not just once that you reuse over and over:
var form = new multiparty.Form();
So, for starter move that into your request handler. Then, if you're unsure how to use the results, I'd suggest you add this:
console.log(fields, files);
And, this should show you what data you actually have.
FYI, you can see errors in the parsing with this:
form.on('error', function(err) {
console.log('Error parsing form: ' + err.stack);
});
Also, note this statement from the documentation:
If cb is provided, autoFields and autoFiles are set to true and all
fields and files are collected and passed to the callback, removing
the need to listen to any events on form. This is for convenience when
you want to read everything, but be sure to write cleanup code, as
this will write all uploaded files to the disk, even ones you may not
be interested in.
You will need to cleanup files on disk after each request or they will accumulate.

Related

How to read sheet data of uploaded file with using sheetJS and node?

So the file uploaded is an excel file that sheetJS needs to read, otherwise it will show as {}.
app.post('/sendExcel', function(req, res) {
let data = req.body;
var workbook = sheetJS.read(data, {type: 'buffer'});
console.log(workbook.Sheets['Sheet1); //prints... "{ A1: { t: 's', v: '[object Object]' }, '!ref': 'A1' }"
let excel = workbook.Sheets['Sheet1']['A1']['v'][0]; //prints... "["
So I've tried various things including changing the type client side as I had problems with it being of type buffer. So now it works partially, but I still can't access the data in the sheet.
As an example, I used the file path instead here, and it's shown to work as normal.
app.get('/excel', function(err, res, data) {
var wb = sheetJS.readFile("data.xlsx");
let excel = wb.Sheets['Sheet1']['A1']['v'];
console.log(excel); //this prints "vehicle", which is what is supposed to happen, not "[".
res.send(excel)
});
I am supposed to get the excel data from the form upload. That's the issue. It is is now successful when sending to the db, but will not access the whole data. I believe I need to change it back to an array.
You can use:
var fileReader = new FileReader();
fileReader.readAsArrayBuffer(workbook);
But this will not run in app.js
Here is my other answer with client-side and server-side. It might be helpful to others.
Javascript Read Excel file on server with SheetJS
Don't use the file reader. Append the excel sheet to the form in the body normally.
Client side:
let excelInput = document.getElementById("fileToUpload");
//excelInput: this html element allows you to upload the excel sheet to it
let excelFile = excelInput.files[0];
let form = new FormData();
form.append("excel", excelFile);
fetch('/sendExcel', {method: "POST", body: form})
.then((data) => {
console.log('Success:', data);
})
.catch((error) => {
console.error('Error:', error);
});
Then use formidable server side.
Server side:
const sheetJS = require('xlsx');
const formidable = require('formidable');
app.post('/excel', function(req, res) {
let data = req.body;
const form = formidable({ multiples: true });
form.parse(req, (err, fields, files, next) => {
if (err) {
next(err);
return;
}
var f = files[Object.keys(files)[0]];
var workbook = sheetJS.readFile(f.path);
res.send(workbook);
});
});
So formidable has to be used otherwise it won't work. Then you can use sheetJS.readFile instead of sheetJS.read.

how to create a pdf file and download it through a nodejs application

I want to create a button through my nodejs application, in order to generate a file (pdf), which the client can download, the file information is filled from the postgres database.
I want help thanks
You can use html-pdf node.js module: https://www.npmjs.com/package/html-pdf
var fs = require('fs');
var pdf = require('html-pdf');
var html = fs.readFileSync('./test/businesscard.html', 'utf8');
var options = { format: 'Letter' };
pdf.create(html, options).toFile('./businesscard.pdf', function(err, res) {
if (err) return console.log(err);
console.log(res); // { filename: '/app/businesscard.pdf' }
});
Then you can return the link to the created file to the client.
You can use this library or something similar to create a pdf: PDFKit. Then you will have to return the PDF to the client. Be sure to add the header: 'Content-Type': 'application/pdf'.

Async Nested Callbacks using Express + Request node module in a MVC structure

I'm struggling with what feels like the final step in passing some data from a model file back into a controller using Node Request.
I've successfully set up a callback from my model file which uses request to load JSON from an external source.
My controller can access this, but I think I still need some kind of nested second callback in the final step as I want the variable pageJSON to contain the JSON object and can't quite figure out how.
Think I've hit a bit of a brick wall with this and some fresh eyes on the problem would be appreciated! It feels like I'm missing something really simple at this point (I hope!)
My model file:
module.exports = function (config, callback) {
const request = require('request');
const options = {
'url' : config.urls.page,
'json' : true,
'auth': {
'user': config.auth.username,
'pass': config.auth.password
}
};
request(options, (error, response, body) => {
if (error) {
console.log(error);
}
callback(body);
});
}
My controller file:
const express = require('express');
const router = express.Router();
const app = express();
const config = require('../config');
const page = require('../models/page');
let pageJSON = page(config, (json) => {
console.log(json); // This shows the JSON structure in console
return json;
});
console.log(pageJSON); // Undefined
// Manipulate JSON and pass request view accordingly using Express
You will have to deal with json manipulation within your controller callback (or call another callback from it):
let pageJSON = page(config, (json) => {
console.log(json); // This shows the JSON structure in console
processJSON(json);
});
pageJSON is undefined because nothing is returned from your model.

Create and Send Zip file -NODE JS

I'm trying to create and then send zip file to client. I know how to create it but I've got a problem with send it to client. I tried many ways.
I'm sending POST request from Client and as response I want to send a file.
This is my server-site example code
var Zip = require('node-zip');
router.post('/generator', function(req, res, next) {
var zip = new Zip;
zip.file('hello.txt', 'Hello, World!');
var options = {base64: false, compression:'DEFLATE'};
fs.writeFile('test1.zip', zip.generate(options), 'binary', function (error) {
console.log('wrote test1.zip', error);
});
res.setHeader('Content-disposition', 'attachment; filename=test1.zip');
res.download('test1.zip');
}
});
I also tried something like this:
res.setHeader('Content-disposition', 'attachment; filename=' + filename);
res.setHeader('Content-type', mimetype);
var filestream = fs.createReadStream(file);
filestream.pipe(res);
I tried to use such libraries as:
node-zip
archiver
Can anyone explain me how to do that ?
This module works fine too: https://www.npmjs.com/package/adm-zip
Example without creating temporary zip file in server:
var AdmZip = require('adm-zip');
router.get('/zipFilesAndSend', function(req, res) {
var zip = new AdmZip();
// add local file
zip.addLocalFile("./uploads/29/0046.xml");
// get everything as a buffer
var zipFileContents = zip.toBuffer();
const fileName = 'uploads.zip';
const fileType = 'application/zip';
res.writeHead(200, {
'Content-Disposition': `attachment; filename="${fileName}"`,
'Content-Type': fileType,
})
return res.end(zipFileContents);
});
Try this express-easy-zip npm package to generate a zip file from a local folder path and send it as a download to the client.
var zip = require('express-easy-zip');
var app = require('express')();
app.use(zip());
app.get('my-route/zip', async function(req, res) {
var dirPath = __dirname + "/uploads";
await res.zip({
files: [{
path: dirPath,
name: 'Package'
}],
filename: 'Package.zip'
});
});
I haven't worked with node-zip or archiver before (I usually just use the built-in zlib module), but one thing I noticed right away is that you should place res.download inside the callback of writeFile. That way it will only send the file once it has been fully written to disk.
fs.writeFile('test1.zip', zip.generate(options), 'binary', function (error) {
res.download('test1.zip');
});
I hope this solution works for you, if it doesn't feel free to comment.
Also, I think res.download sets the Content-disposition header for you, you don't need to set it manually. Not 100% sure on that one though.
Above solutions work.(above solutions generate zip and send it to frontend as data in response. In order to make it as downloadable following code will work) I was using express-zip. It is compressing files and sending data to frontend from backend(node). But in frontend I was getting only data in response. In my case I want user can be able to download the zip which sent by server. To solve this I followed following approach. For generating download window in browser i used downloadjs (we can follow another approach but i find this easy)
Front-End
const download = require('downloadjs')
return axios({
url:process.env.API_HOST+'/getuploadedfiles',
method:'get',
headers:{
'Content-Type': 'multipart/form-data',
withCredentials:true,
},
responseType:'arraybuffer' // If we don't mention we can't get data in desired format
})
.then(async response => {
console.log("got al files in api ");
let blob = await new Blob([response.data], { type: 'application/zip' }) //It is optional
download(response.data,"attachement.zip","application/zip") //this is third party it will prompt download window in browser.
return response.data;
})
Backe-End
const zip = require('express-zip');
app.use('/getuploadedfiles',function(req,res){
res.zip([
{path:'/path/to/file/file2.PNG',name:'bond.png'},
{path:'/path/to/file/file1.PNG',name:'james.png'}
])

HTTP request from within Express/Node.js

I'm trying to set up an express service for a program that I'm writing that contacts an external API and then returns the results so it can be stored in a Mongo I have set up.
This seems like it should be fairly straightforward, but I'm new to Node.js/Express and I'm getting a "Can't set headers after they are sent" error.
I'm getting the data that I want from the external API, but how to send that data properly back to my Angular app.js so it can update in my table?
"addSelected()" is the function I'm calling in my app.js to kick off the process. The "data" prints part of the way through the full response but then cuts off and gives me the "Can't set Headers after they are sent" error. From what I understand this is from sending the response and then trying to modify the response header after the fact.. but I'm unsure of a workaround or if I'm just formatting everything wrong as this is my first swing at MEAN stack in general.
I know the problem is on the line "res.send(data)" in server.js but I don't know how to correctly format the response.
My code:
server.js
//server.js
//setup ==============================
var express = require ('express');
var request = require('request');
var app = express();
var mongoose = require('mongoose');
var https = require('https');
//config ============================
app.use(express.static(__dirname + '/public/'));
console.log("running PipeHelper");
mongoose.connect('mongoedit');
var Schema = mongoose.Schema;
var opSchema = new Schema({
title: String,
description: String,
company: String,
post_date: String,
close_date: String,
contact: String,
location: String,
url: String,
notice_type: String
});
var item = mongoose.model('item', opSchema);
//routes===========================
//returns full database
app.get('/api/db', function(req, res){
item.find({},function(err, items){
if (err) res.send(err);
res.json(items);
});
});
//searches FBO for opportunities to add to database
app.get('/api/search:FBO_key', function(req, res){
var data;
console.log("2");
var baseURL = "api.data.gov"
var params = "/gsa/fbopen/v0/opps?q=" + req.params.FBO_key;
params += "&api_key="+"keyyyy";
params += "&all";
params += "&start=0";
params += "&p=1";
params += "&limit=10";
url = baseURL+params;
var options = {
port: 443,
host: 'api.data.gov',
path: params,
method: 'GET'
};
//get FBO data
var request = https.request(options, function(response){
console.log("4");
response.on('data', function (chunk){
//response data to send back to app.js
data += chunk.toString();
res.send(data);
});
});
console.log("3");
request.end();
request.on('error', function(e){
console.error(e);
});
});
app.get('/', function(req,res){
res.sendfile('./public/index.html');
});
app.listen(8000);
app.js
var app = angular.module("pipeHelper", ['smart-table']);
app.controller('mainCtrl', [
'$scope', '$http', function($scope, $http){
$scope.selected = [];
$scope.displayData= [];
$scope.items=[];
$scope.FBOsearch;
//populates table on startup with whole DB
$http.get('./api/db')
.success(function(data){
$scope.items=data;
$scope.displayData = [].concat($scope.items);
})
.error(function(data){
console.log('Error: '+data);
});
$scope.addSelected = function(){
//search FBO, add opportunities, update table
console.log("1");
$http.get('./api/search'+'NGA')
.success(function(data){
console.log("5");
console.log(data);
$scope.items=data;
$scope.displayData= [].concat($scope.items);
})
.error(function(data){
console.log('Error: ' +data);
});
};
$scope.isSelected = function(item){
//if its selected, remove it
// if its unselected, add it
if ($scope.selected.indexOf(item)==-1){
$scope.selected.push(item);
}
else{
$scope.selected.splice($scope.selected.indexOf(item), 1);
}
console.log($scope.selected);
//temp placeholder function. Eventually add to array of selected objects for placement in Pipeliner/deletion
};
}]);
solved the issue. I was unaware that response.on('data') gets called multiple times, thus calling my res.send(data) multiple times and incompletely causing it to crash with the error. I added the following to the request function:
response.on('end'function(){
res.send(data);
};
basically when the external API data is finished coming in, send it with express. Learn by doing I suppose. Hope this helps someone eventually.
I can't leave a comment, so I will just make it an answer.
I would recommend installing node-inspector, npm install -g node-debug. Then run your app with node-debug server.js. This will spawn a new instance of Firefox or Chrome dev tools and allows you to debug your nodeJS code. Very useful.
The error you are seeing is most likely related to request.end(), if I were to guess. After .end() is called, you can no longer modify the header content. I doubt it would make a difference, but try putting the request.end() after you have the request.on('error') call.
EDIT: 10/15/15
I would highly recommend installing VS Code. It has a built-in debugger for node apps.

Categories

Resources