ReactJS download file from Express Server - node.js

I'm trying to make my user able to download a file from our backend server. I've tried the solution from this question as well as the backend from this.
Sadly none of them worked. The download itself works through postman, but not in react.
Additional info: The Backend is running on the same machine but on port 3001 while the frontend is running on port 3000
I'm not sure if that helps, but the react frontend is connected to the backend via proxy in the package.json
"proxy": "http://localhost:3001",
The client side currently looks like this:
const download = require("downloadjs");
const handleDownload = async () => {
const res = await fetch("http://localhost:3001/download");
const blob = await res.blob();
download(blob, "test.pdf");
}
function App() {
return (
<div className="App">
<header className="App-header">
<button onClick={() => handleDownload().finally(() => console.log("Passed through the whole handleDownload Request"))}> </button>
</header>
</div>
);
}
while on the backend side I'm using this code as from the previous questions asked here on stackoverflow.
app.get('/getdoc', function (req, res) {
res.download(path.join(__dirname, 'files/test.pdf'), function (err) {
console.log(err);
});
});
This is the Code working through Postman, but it won't trigger a download in React.
The Error occurring in react looks like this:
App.js:8 GET http://localhost:3001/download/test.pdf net::ERR_CONNECTION_REFUSED
Uncaught (in promise) TypeError: Failed to fetch
So it seems the handling on frontend seems to be the problem, as it is not triggering the Save Dialog from the browser (Chrome).

Your request to postman will work because I assume you are hitting the correct endpoint which is '/getdoc' which will let you download the pdf via postman.
However, your fetch request does not seem to match the API endpoint that serves the pdf document. That is why your React Component will give you the error on download.
const handleDownload = async () => {
const res = await fetch("http://localhost:3001/download");
const blob = await res.blob();
download(blob, "test.pdf");
}
//the fetch call for "http://localhost:3001/download" will not hit '/getdoc'
app.get('/getdoc', function (req, res) {
res.download(path.join(__dirname, 'files/test.pdf'), function (err) {
console.log(err);
});
});
Here is how I implemented the pdf download.
//resume route... this route is hit when you make a GET request to /api/resume
const router = require('express').Router();
module.exports = router;
//when route is hit the resume is downloaded
//aka /api/resume
router.get('/', (req, res, next) => {
try {
const file = `${__dirname}/resume/resume.pdf`;
res.download(file);
console.log('here');
} catch (err) {
console.log(err);
}
});
//react component
import React from 'react';
import download from 'downloadjs';
const Resume = () => {
return (
<div>
<button
type="button"
onClick={async () => {
const res = await fetch('/api/resume');
const blob = await res.blob();
download(blob, 'test.pdf');
}}
>
Download
</button>
</div>
);
};

Try this:
const handleDownload = () => {
var reqObj = new XMLHttpRequest();
reqObj.open('GET','http://localhost:3001/download',true); // 'getpdf' is the URI to recongize your request at the server
reqObj.send();
reqObj.onreadystatechange = function() {
var resObj = this;
if(resObj.readyState == resObj.DONE) {
if (resObj.status != 200) {
console.log(200);
} else if (resObj.status == 200){
var resTxt = reqObj.responseText;
window.location.assign(resTxt); // Opens the pdf download prompt
}
}
}

Related

Fetch request not fetching backend object - nextjs and express

I have a Nextjs frontend trying to make a fetch request to my node and express backend but it's not happening for some reason. I'm trying to access this object in the backend: {"data": ["data1", "data2", "data3"]} but I'm not able to even fetch it. Here is my backend code:
const express = require('express')
const app = express()
app.get("/api", (req, res) => {
res.json({"data": ["data1", "data2", "data3"]})
})
app.listen(5000, () => { console.log("Server started on port 5000") })
Here is my next.js file trying to make this request:
import React, { Component, useEffect, useState } from 'react';
const Product = () => {
const [backendData, setBackendData] = useState([{}])
useEffect(() => {
fetch("/api").then(
response => response.json()
).then(
data => {
setBackendData(data)
}
)
}, [])
return (
<div>
{(typeof backendData.data === 'undefined') ? (
<p>Loading...</p>
) : (
backendData.data.map((data, i) => (
<p key={i}>{data}</p>
))
)}
</div>
);
}
export default Product
I've included this line in my package.json file "proxy": "http://localhost:5000", so it should be going to that link and when I search http://localhost:5000 in my browser, I get the object that I've written in the backend like this: {"data":["data1","data2","data3"]}.
When I click on Network when I hit inspect on the page, the fetch request doesn't show up either.
Does anyone know why I'm unable to fetch this object in nextjs?

Passing parameters using React fetch to access Node API

I have a react project with NODE API backend. I am facing issues with the very basic fetch GET request. When passing parameters through link, it cannot be accessed at the server side.
My react function:
const loadOptions = async (cnt) => {
const response = await fetch(`${baseurl}/pdt/prev=${prev}&cnt=${cnt}`);
const resJSON = await response.json();
};
NodeJS express router code:
router.get("/pdt/:prev/:cnt", async (req, res) => {
try {
console.log(req.params.cnt);
console.log(req.params.prev);
} catch (err) {
res.json(err.message);
}
});
The result is :
Edited React code based on the answers I got above. Thank you #Phil
const response = await fetch(`${baseurl}/pdt/${prev}/${cnt}`);
It's working now.
another solution from backend
router.get("/pdt", async (req, res) => {
try {
console.log(req.query.prev);
console.log(req.query.cnt);
} catch (err) {
res.json(err.message);
}
});
and modify request
fetch(`${baseurl}/pdt?prev=${prev}&cnt=${cnt}`)

Get external api with axios and req body to url for search and ajax NodeJS express

I use node.js expess with MVC pattern and use axios for get json url. The all logic request api i wrote it in Controller , I try to create some get api with axios like this.
this my chartController.js , it's some logic for get json from url with req.body.symbol (it's just symbol of stock from user submitted input form , I want to get that symbol to my axios get url in code below in const chartChartPage )
'use strict';
const axios = require('axios');
const request = require('request');
/* For Get my Api Token Data */
const dataTokens = require('../config/apitokens');
const chartChartPage = async (req,res) => {
try {
const symbol = req.body.symbol;
const url = `https://${dataTokens.sandbox}.iexapis.com/stable/stock/${symbol}/chart/1m?token=${dataTokens.tokens}`;
const fetchData = await axios.get(url);
res.status(200).json(fetchData.data);
}
catch (error){
res.status(400).send(error.message);
}
}
module.exports = {
chartPage,
chartChartPage
}
Now, i have to added some routes in my chart.js
i think i should add router.post('/', chartChartPage) for get that symbol in input when user submitted Maybe i'm wrong.
var express = require('express');
var router = express.Router();
var {chartPage , chartChartPage} = require('../controllers/chartControllers');
router.get('/', chartPage);
router.post('/', chartChartPage);
module.exports = router;
and in my chartChartPage.js (it's just js file for my template)
and use ajax to get that data from url above (with chartChartPage) to get data for build chart stock
and try to console.log that data but that's not work in console
$(function(){
chartChartPage();
});
const chartChartPage = async () => {
await $.ajax({
url: '/chart',
type: 'POST',
dataType: 'json',
success: (response) => {
if (response != null) {
console.log(response);
}
},
error: (err) => {
console.log(err);
}
});
}
and when i submitted form i got that all json data in my page, but i want when submitted it's render to same page and work in console.log in ajax get url above. How can i fix.?
enter image description here

Download CSV file from browser after making axios call from React to Nodejs Api

I have MERN application and I want to download a CSV file on button click. I implemented everything but when I click the button there is no download in browser.
Axios call
const handleDownloadCsv = async () => {
try {
await axios.get('http://localhost:2000/users/admin-panel/csv');
} catch (error) {
console.log(error);
}
};
NodeJs controller
export const admin_panel_csv = async (req,res) => {
try {
let __dirname = res.locals.__dirname;
const myReadStream = fs.createReadStream(__dirname + '/documents/admin_csv.csv');
//myReadStream.pipe(res);
res.download(__dirname + '/documents/admin_csv.csv')
} catch (error) {
console.log('Error csv: ',error.message);
res.status(400).json({msg:error.message});
}
}
I've tried both createReadStream(with pipe) and res.download(path to file) but non of them seams to work. I am not getting any errors when making this api call through axios. Is there some way to accomplish this without using React libraries.
There is no download prompt in the browser since you are initiating the download via axios and not through the browser (e.g., through a <form> POST or an <a> click).
Change the back-end code back to res.download and on the front-end, initiate the download through an <a> click:
const handleDownloadCsv = () => {
const tempLink = document.createElement('a')
tempLink.href = 'http://localhost:2000/users/admin-panel/csv'
tempLink.click()
}
I think that you should use js-file-download in React and just :
const FileDownload = require('js-file-download');
Axios.get(API_URL + "download")
.then((response) => {
FileDownload(response.data, 'file.txt');
});

Posting data from EJS to Node.js

I have an index.html EJS rendered by a koa/Node.js app which contains a javascript snippet to post data about the current page to the same app, to an endpoint to save in a database.
The javascript code ( an AJAX fetch POST) reaches the Node.js endpoint but doesn't transmit any data. I don't see any typo in the code.
[CORRECTION] indeed a typo with the bodyparser
# index.js
const Koa = require("koa");
const path = require("path");
const render = require("koa-ejs");
const bodyParser = require("koa-bodyparser");
const router = require("./routes/routes.js");
const app = new Koa();
render(app, {
root: path.join(__dirname, "/views"),
layout: false,
viewExt: "html",
});
app
.use(bodyParser())
.use(router.routes())
.use(router.allowedMethods())
.use(staticCache("./images", { maxAge: 600000 }))
.listen(PORT, () => {
console.log(`Running on port ${PORT}`);
});
In the index.html, I have a button that triggers a POST request to an endpoint (/node/insert) of the koaRouter. The action is to save information about the current page (say, document.location.href) in a Postgres database.
# /views/index.html
[...]
<form id="newRow">
<input type="submit" value="New row">
</form>
[...]
<script type="module" src="fetch.js" async></script>
where:
# /views/fetch.js
const data = {
app: "Node",
url: document.location.href,
...
};
document.getElementById("newRow").addEventListener("submit", (e) => {
e.preventDefault();
fetch("/node/insert", {
method: "POST",
headers: {
"Content-Type": "application/json; charset-UTF-8",
},
body: JSON.stringify(data),
})
.then((res) => {
if (res.ok) {
return res.json();
}
return Promise.reject(res);
})
.then((res) => console.log("front", res))
.catch((err) => console.warn(err));
Among the routes, I defined an endpoint /node/insert to respond to this action:
# routes.js
const koaRouter = require("koa-router");
const router = new koaRouter();
router.post("/node/insert", async (ctx) => {
console.log("posted", ctx.request.body);
^^^ "posted" is positively printed in terminal after submit
if (ctx.request.body) {
return (ctx.response.status = 200)
} else {
return (ctx.response.status = 404); <-- check
}
})
The endpoint "/node/insert" is reached since I can console.log positively, but the body isn't passed to the endpoint: ctx.request.body = {}. I have the following error:
"SyntaxError: Unexpected token O in JSON at position 0"
detected from fetch.js (probably because the body is {}?).
I don't see what is wrong.
Note: the Node app runs in a container (pm2-runtime start index.js) and use Nginx as reverse proxy, static files server and load-balancer`
Try:
const koaJson = require(koa-json);
app.use(koaJson());
Just a typo in the bodyparser as Evert pointed and bad positioning of the middleware
curl --data "app=Node" HTTP://localhost:8000/node responds normaly.

Resources