Mysql data to Excel File - node.js

I am working on nodeJs and React, I have data in mysql storage.
ultimately i need to let the user to download the data in excel format.
Either we can do in nodeJs or React.
I tried to create a file in Node using excel4node package, The file gets created successfully, but when i send the file, it is not in excel format(some xml files and folders), i used downloadJs in frontend to trigger autoDownload.
router.get('/:year/:month', async (req, res, next) => {
res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
res.setHeader('Content-Disposition', 'attachment; filename=' + 'Report.xlsx');
res.sendFile(path.resolve('downloads/excel.xlsx'));
});
import downloadjs from 'downloadjs';
export const getReport = async (year, month) => {
let res = await fetch(`${url}/get-report/${year}/${month}`, {
method: 'GET',
mode: 'cors',
})
let blob = await res.blob();
await downloadjs(blob);
};
This downloads a zip folder which has list of xml files.
I tried to create in React (client side) by sending json from the backend,
for this i used react-excel-workbook package, but it needs a predefined data, when we click, it suddenly gets downloaded with dummy data and it doesn't wait for async action to resolve.
Any help will be appreciated.
Or should i send the json from backend and on client side (convert it into csv and trigger download.??

Write the file directly to the Response object, instead of going through an intermediate file
var xl = require('excel4node');
var wb = new xl.Workbook();
// sends Excel file to web client requesting the / route
// server will respond with 500 error if excel workbook cannot be generated
var express = require('express');
var app = express();
app.get('/', function(req, res) {
wb.write('ExcelFile.xlsx', res);
});
app.listen(3000, function() {
console.log('Example app listening on port 3000!');
});

Late answer but you should specify content type when you are creating the blob in your frontend, then create a link in your DOM and specify to browser that the file must be downloaded :
axios.get(`${your backend url goes here}/path/to/export`, {
responseType: 'blob',
headers: {
'Authorization': `Bearer ${token}` //Or any auth method
}
}).then(res => {
const url = window.URL.createObjectURL(new Blob([res.data]), {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'}); //specify CT
const link = document.createElement('a'); // attach link to DOM
link.href = url;
link.setAttribute('download', 'File.xlsx');
document.body.appendChild(link);
link.click(); // Auto dl the file
link.remove(); // Remove the link
}).catch(err => {
console.log(err);
})

Related

Send Blob File from html form to express server so it can be uploaded to cloud

So I'm trying to make the html form:
<form action="blahblah" encblah="multipart/form-data" whatever>
Thats not the problem, I need to make that form send the blob to express
app.post('/upload/avatars', async (req, res) => {
const body = req.body;
console.log(req.file);
console.log(body);
res.send(body);
});
So I can access the blob, create a read stream, pipe it to the cloud, and bam, upload the file without downloading anything on the express server it self.
Is that possible?
If yes, please tell me how.
If no, please tell me other alternatives.
On the client we do a basic multi-part form upload. This example is setup for a single image but you could call uploadFile in sequence for each image.
//client.ts
const uploadFile = (file: File | Blob) => {
const formData = new FormData();
formData.append("image", file);
return fetch("/upload", {
method: "post",
body: formData,
});
};
const handleUpload = (event: any) => {
return event.target.files.length ? uploadFile(event.target.files[0]) : null;
};
On the server we can use multer to read the file without persisting it to disk.
//server.js
const express = require("express");
const app = express();
const multer = require("multer");
const upload = multer();
app.post(
"/upload",
upload.fields([{ name: "image", maxCount: 1 }]),
(req, res, next) => {
console.log("/upload", req.files);
if (req.files.image.length) {
const image = req.files.image[0]; // { buffer, originalname, size, ...}
// Pipe the image.buffer where you want.
res.send({ success: true, count: req.files.image.originalname });
} else {
res.send({ success: false, message: "No files sent." });
}
}
);
For larger uploads I recommend socket.io, but this method works for reasonably sized images.
it is possible, but when you have a lot of traffic it would overwhelm your express server (in case you are uploading videos or big files ) but if it's for uploading small images (profile image, etc...) you're fine. either way you can use Multer npm
I'd recommend using client-side uploading on ex: s3-bucket, etc..., which returned a link, and therefore using that link.

How do I create a file in express and node on my server and then download it to my client. I am using NextJS for my frontend and backend

How do I create a file in express and node on my server and then download it to my client. I am using NextJS for my frontend and backend. I am confused on how I would download the file on the front end after the file is created on the root of the server folder. Since I am using React for my frontend whenever I try to visit that filepath it tries to take me to a page instead of the file
Here is what I have in my express route in node
var xls = json2xls(json, {
fields
});
// If there isn't a folder called /temp in the
// root folder it creates one
if (!fs.existsSync('./temp')) {
fs.mkdirSync('./temp');
}
const fileName = `temp/${req.user.first_name}${req.body._id + Date.now()}.xlsx`
// fs.writeFileSync(fileName, xls, 'binary');
fs.writeFile(fileName, xls, 'binary', function (err, result) {
if (err) {
return console.log(err);
}
console.log(result, 'this is result')
});
Here is what I have on my frontend
axios.post('api/download',payload)
.then(res => {
const link = document.createElement('a');
link.href = res.data.url;
link.download
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
})
.catch(err => {
throw err
})
Can you make request with GET on api, and.
Make request with GET.
Make temp directory to be static resources directory:
app.use(express.static('temp')); // app is your express instance.
// Maybe you have to correct temp's path
Response the post request with file url data
fs.writeFile(fileName, xls, 'binary', function (err, result) {
if (err) {
return console.log(err);
res.status(500).json({err});
}
console.log(result, 'this is result');
res.json({url: 'http://localhost:8080/temp/' + fileName}); // res is response object of you router handler.
// Maybe you have correct the server address
});
On other way, you can send the xls binary direct to client, in the client you create a BLOB object from the response, then create download link for the blob object.

Node.js How to zip an array of images and force browser to download it

as the title says. I have an app that could collect all image urls from an user input url. Now I want to able to zip them and when the user press the download button, it will fires a request contain the array of all the image urls to download.js and let the download.js to process the download.
In addition, I am using express.js and react; the express.js is using port 5000
Someone sent me a working sample code: https://repl.it/#chiKaRau/picture-packer-4-rex-1
However, this code will create its own port 3000
I want to able to process the download on my current port 5000 while express is launch on port 5000
So I changed some code, however, once I pressed the download button, nothing happens (no error and no download)
Would anyone tell me how to solve this? Thank
download.js
const express = require('express');
let router = express.Router();
const fetch = require('node-fetch')
// to get the images const
JSZip = require('jszip')
// to zip them up
const micro = require('micro')
// to serve them
router.post('/download-pics', (req, res) => {
const files = [
{
url: "https://jeremyliberman.com/static/489f2e7cf7df14bc2c8ac2bc8c76aa59/cb864/avatar.png",
file: 'avatar.png'
},
{
url: "https://jeremyliberman.com/static/489f2e7cf7df14bc2c8ac2bc8c76aa59/cb864/avatar.png",
file: 'avatar1.png'
},
{
url: "https://jeremyliberman.com/static/489f2e7cf7df14bc2c8ac2bc8c76aa59/cb864/avatar.png",
file: 'avatar2.png' }
]
// Start a simple web service with one route
// Create an in-memory zip file
var zip = new JSZip();
// Fetch each image source
const request = async () => {
for (const { file, url } of files) {
const response = await fetch(url);
const buffer = await response.buffer();
zip.file(file, buffer);
}
}
request();
// Set the name of the zip file in the download
res.setHeader('Content-Disposition', 'attachment; filename="pictures.zip"')
// Send the zip file
zip.generateNodeStream({ type: 'nodebuffer', streamFiles: true })
.pipe(res).on('finish', function() {
console.log("out.zip written.");
}) })
//export this router to use in our index.js module.exports = router;
Function request returns a promise. You need to wrap the rest of the code after request() in then(() => {})
request()
.then(() => {
// Set the name of the zip file in the download
res.setHeader('Content-Disposition', 'attachment; filename="pictures.zip"')
// Send the zip file
zip.generateNodeStream({ type: 'nodebuffer', streamFiles: true })
.pipe(res).on('finish', function() {
console.log("out.zip written.");
})
})

Display PDF file in ReactJS that is received from a Node.js server?

I am trying to build a system where a user can store pdf files on a server, and another user can view those pdf files by using a simple click on a file link.
I am trying to store a file in a MySQL database and retrieve it using app.get(). I have successfully stored the file in the database using BLOB, but when I try to retrieve it, it is in some other format.
I have also tried to store the file in local folder ./uploads using 'express-fileupload', but that also doesn't seem to work when I try to retrieve the file location. After receiving the file location I am sending it back to my React app, and then try to open it using embed and iframe tags.
I have also tried 'react-pdf', 'simple-react-pdf', but nothing seems to work.
Below is the code that is written on server side that is sending the pdf file. I have also tried sending the location of pdf file that is stored in location provided in the code below. But that also doesn't work.
app.get('/getFile', (req, res) => {
const {email, courseid, filename} = req.query;
console.log(email);
console.log(courseid);
console.log(filename);
var filePath = `${__dirname}`+'/uploads/'+`${filename}`;
fs.readFile(filePath , function (err,data){
console.log(data);
res.contentType("application/pdf");
res.send(data);
});
});
This worked for me:
Node:
app.get("/getFile", function(req, res) {
res.sendFile(__dirname + "/test.pdf");
});
React:
axios(`http://localhost:5000/getFile `, {
method: "GET",
responseType: "blob"
//Force to receive data in a Blob Format
})
.then(response => {
//Create a Blob from the PDF Stream
const file = new Blob([response.data], {
type: "application/pdf"
});
//Build a URL from the file
const fileURL = URL.createObjectURL(file);
//Open the URL on new Window
window.open(fileURL);
})
.catch(error => {
console.log(error);
});

Sending Zip file from server to client browser with Express and Archiver

I am a beginner with Node and I am trying to figure out how to create a zip file at the server then send it to the client and then download the zip file to the user's browser. I am using the Express framework and I am using Archiver to actually do the zipping. My server code is the following which was taken from Dynamically create and stream zip to client
router.get('/image-dl', function (req,res){
res.writeHead(200, {
'Content-Type': 'application/zip',
'Content-disposition': 'attachment; filename=myFile.zip'
});
var zip = archiver('zip');
// Send the file to the page output.
zip.pipe(res);
// Create zip with some files. Two dynamic, one static. Put #2 in a sub folder.
zip.append('Some text to go in file 1.', { name: '1.txt' })
.append('Some text to go in file 2. I go in a folder!', { name: 'somefolder/2.txt' })
.finalize();
});
So its zipping two text files and returning the result. On the client side I am using the following function in a service to actually call that endpoint
downloadZip(){
const headers = new Headers({'Content-Type': 'application/json'});
const token = localStorage.getItem('token')
? '?token=' + localStorage.getItem('token')
: '';
return this.http.get(this.endPoint + '/job/image-dl' + token, {headers: headers})
.map((response: Response) => {
const result = response;
return result;
})
.catch((error: Response) => {
this.errorService.handleError(error.json());
return Observable.throw(error.json());
});
}
and then I have another function which calls downloadZip() and actually downloads the zip file to the user's local browser.
testfunc(){
this.jobService.downloadZip().subscribe(
(blah:any)=>{
var blob = new Blob([blah], {type: "application/zip"});
FileSaver.saveAs(blob, "helloworld.zip");
}
);
}
When testfunc() is called, a zip file is downloaded to the user's browser however when I try to unzip it it creates a zip.cpgz file which then turns back into a zip file when clicked in an infinite loop which indicates that some kind of corruption happened. Can anyone see where I went wrong here?

Resources