How to download a file from an api in react - javascript

How to download a file from an API response which is in a different format ?
await axios.get(`/dashboard/reportdownload/?file_name=242424242.pdf`,{
headers: {
"Authorization": `Bearer 767958756576576576jgjhgjhg`
}
})
.then((res) => {
console.log(res?.data);
});
In response I am getting
How do download it with reactjs

You need to check if the response from the API is of type blob, then convert it. For example, if it is clear you are expecting a PDF response, try this:
await axios.get(`/dashboard/reportdownload/?file_name=242424242.pdf`, {
headers: {
'Authorization': `Bearer 767958756576576576jgjhgjhg`
}
})
.then((response) => {
let fileName = '242424242.pdf';
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
// IE variant
window.navigator.msSaveOrOpenBlob(
new Blob([response.data], {
type: 'application/pdf',
encoding: 'UTF-8'
}),
fileName
);
} else {
const url = window.URL.createObjectURL(
new Blob([response.data], {
type: 'application/pdf',
encoding: 'UTF-8'
})
);
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', fileName);
document.body.appendChild(link);
link.click();
link.remove();
}
});

Related

Download pdf file from server response

So, I am creating a docx with php laravel, then converting to pdf and save it in my public server folder. Finally, I am sending a response to my client with the file.
Now, in client side, I am tryng to download it.
It's half working, because I can download a file (with exact same page number) but the file and all the page are blank page.
Here, server side sending my file to client side
$docx->transformDocument($fileName . '.docx', $fileName . '.pdf');
return response()->file(public_path($fileName . '.pdf'));
What I have tried client side
export const generateDocx = (offerData) => async () => {
await axios({
method: 'post',
url: `${process.env.REACT_APP_API_URL2}offer/generate/docx`,
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
responseType: 'arraybuffer',
},
data: offerData,
}).then((res) => {
console.log(res);
// Create blob link to download
const url = window.URL.createObjectURL(new Blob([res.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', `FileName.pdf`);
document.body.appendChild(link);
link.click();
link.parentNode.removeChild(link);
});
};
what my console.log (res) contain :
I have also tried this :
let fileName = 'aaa.pdf';
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveOrOpenBlob(
new Blob([res.data], {
type: 'application/pdf',
encoding: 'UTF-8',
responseType: 'blob'
}),
fileName
);
} else {
const url = window.URL.createObjectURL(
new Blob([res.data], {
type: 'application/pdf',
encoding: 'UTF-8',
})
);
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', fileName);
document.body.appendChild(link);
link.click();
link.remove();
}
console.log(res.data);
});
And with file-saver package
var blob = new Blob([res.data], {
type: 'application/pdf',
});
saveAs(blob, 'hello world.pdf');
});
what my blob console.log contain :
After some test it's working
export const generateDocx = (offerData) => async () => {
await axios({
method: 'post',
url: `${process.env.REACT_APP_API_URL2}offer/generate/docx`,
responseType: 'blob',
headers: {
Accept: 'application/pdf',
},
data: offerData,
}).then((res) => {
var blob = new Blob([res.data], {
type: 'application/pdf',
});
saveAs(blob, 'test.pdf');
});
};
thank you all for your help

React: How to open PDF in new Tab from Cloud storage without downloading in local pc

I am trying to open pdf from the cloud in a new tab, without downloading it to the local machine.
I tried this way but not working for me. In the new tab, it is giving an error.
function readFileInNewTab (fileId) {
let url = BASE_URL + "api/CMS/Documents/Download/" + fileId;
const requestOptions = {
method: 'GET',
headers: { 'Content-Type': 'application/pdf', ...authHeader(url) },
credentials: 'include',
responseType: "blob", // important
};
inProgress = true;
return fetch (url, requestOptions).then(handleResponse)
.then((response)=> {
const file = new Blob([response], { type: "application/pdf" });
//Build a URL from the file
const fileURL = URL.createObjectURL(file);
//Open the URL on new Window
const pdfWindow = window.open();
pdfWindow.location.href = fileURL;
})
.catch((error) => {
console.log(error);
});
}

Access Headers when using fetch in javascript

I am sending a zip file from my nodejs server to the browser using the following
res.set("Content-Type", "application/octet-stream");
res.set("Content-disposition", `attachment; filename="`+zip_name+`.zip"`);
res.set("Content-Length", zipBuff.length);
res.send(zipBuff);
I am then fetching it by using :
fetch("/my/url", {
method: "POST",
body: formData,
})
.then(response => {
return response.blob();
})
.then(response => {
const blob = new Blob([response], {type: 'application/zip'});
const downloadUrl = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = downloadUrl;
a.download = "blah.zip";
document.body.appendChild(a);
a.click();
});
I would like to be able to use zip_name instead of blah for the filename but I can't figure out how to access the headers (in that case Content-disposition) of the response with fetch.
Could someone please explain how it's done ?
Return blob and headers in object
fetch("/my/url", {
method: "POST",
body: formData,
})
.then(response => {
const headers = response.headers
return { blob: response.blob(), headers }
})
.then(({blob, headers}) => {
/// now you can access to **headers** and blob data
});
UPD:
To access the headers use headers.get("Header name").split('=').pop()
UPD1:
const foo = async () => {
const response = await fetch("/my/url", {
method: "POST",
body: formData,
})
if(!response.ok)
thorw new Error("Some error happend")
const blod_data = await response.blob()
const header_with_name = response.headers.get("Header name").split('=').pop()
// do something with it
}
In the first promise arrow function you have access to the HTTP response headers. If you update it to return the promise from the blob function call. Then in this nested function you can return an object that includes the header value to the outer second arrow function that processes the blob data.
Updated fetch example that includes processing the Promise returned from blob-function call.
fetch("/my/url", {
method: "POST",
body: formData,
})
.then(response => {
return response.blob().then((data) => {
return {
data: data,
filename: response.headers.get('Content-disposition'),
};
});
})
.then(({ data, filename }) => {
const blob = new Blob([data], { type: 'application/zip' });
const downloadUrl = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = downloadUrl;
a.download = filename.split('=')[1];
document.body.appendChild(a);
a.click();
});
Thank you Chapo for pointing out the issue with my previous example

Download CSV files with HttpClient in ReactJS

I'm trying to make an API request using HttpClient to download a CSV file. I had to switch from Axios to HttpClient due to ForgeRock authentication that requires a bearer token. I'm having an issue where the response coming back does not have response.data. Where would I find the data to download to CSV?
My code:
fetchCSV = date => {
const url = "https://<URLdownloadLink>?runDate="+date;
const method = "GET";
HttpClient
.request({
url,
method,
bypassAuthentication: false,
responseType: 'blob',
init: {},
timeout: 5000
})
.then((response) => {
console.log("data", response)
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', 'Asset Manager.csv');
document.body.appendChild(link);
link.click();
link.remove();
})
.catch(error => {
console.log("error", error);
})
}
The response I'm getting back is the below. The response does not have "response.data" as an object key. When I open the CSV it only has "undefined".
This is my response.body:
You are using response.data instead of response.body?
Thats why it says undefined.
Remember CSV is just plain text and response.data is undefined.
fetchCSV = date => {
const url = "https://<URLdownloadLink>?runDate=" + date;
const method = "GET";
HttpClient
.request({
url,
method,
bypassAuthentication: false,
responseType: 'blob',
init: {},
timeout: 5000
})
.then((response) => {
console.log("data", response)
const url = window.URL.createObjectURL(new Blob([response.body]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', 'Asset Manager.csv');
document.body.appendChild(link);
link.click();
link.remove();
})
.catch(error => {
console.log("error", error);
})
}

Creating PDF from request response doesn't work with axios but works in native xhr

In order to force download PDF from server I tried to use axios and native xhr object. The reason is that I have to send post request, because I pass too much data to server, so the option with simple link (like site.ru/download-pdf won't work for me).
Even though I finally managed to do this with Xhr, I still don't have a clue why axios way doesn't work.
Here is how I do this with xhr and it works for me:
let xhr = new XMLHttpRequest()
xhr.open('POST', Vue.config.baseUrl + `order-results/${id}/export-pdf`, true)
xhr.setRequestHeader("Authorization", 'Bearer ' + this.token())
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded")
xhr.responseType = 'arraybuffer'
xhr.onload = function(e) {
if (this.status === 200) {
let blob = new Blob([this.response], { type:"application/pdf" })
let link = document.createElement('a')
link.href = window.URL.createObjectURL(blob)
link.download = 'Results.pdf'
link.click()
}
};
xhr.send("data=" + data);
Here is "axios-way" and I actually get PDF with correct number of pages, but they are all empty:
axios.post(`order-results/${id}/export-pdf`, {
data,
responseType: 'arraybuffer'
}).then((response) => {
let blob = new Blob([response.data], { type:"application/pdf" })
let link = document.createElement('a')
link.href = window.URL.createObjectURL(blob)
link.download = 'Results.pdf'
link.click()
})
Axios is already configured to send Authorization token.
I put Application/x-www-form-urlencoded in xhr because otherwise I couldn't get data in server side.
Even though xhr works, I'd prefer to use axios since I use it everywhere and I'm just curios what I'm doing wrong. I tried different solutions, and only native xhr did the job.
The following works for me:
axios.post("http://localhost:8080/reports/my-report/",
data,
{
responseType: 'arraybuffer',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/pdf'
}
})
.then((response) => {
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', 'file.pdf'); //or any other extension
document.body.appendChild(link);
link.click();
})
.catch((error) => console.log(error));
Let me know if this helps.
Cheers!
For whatever reason the pdf is downloading but any content passed is not appearing resulting in a blank pdf.
I found this code snippet that is similar but results in a pdf with content.
axios({
url: '/pdf',
method: 'GET',
responseType: 'blob', // important
}).then((response) => {
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', 'file.pdf');
document.body.appendChild(link);
link.click();
});
there was some feedback stating that it didnt work on IE 11, I have not tested it but a solution was posted using FileSaver.js
axios({
url: '/pdf',
method: 'GET',
responseType: 'blob', // important
}).then((response) => {
FileSaver.saveAs(new Blob([response.data]));
});
There is a special responseType: 'blob':
axios.post(`order-results/${id}/export-pdf`, {
data,
responseType: 'blob'
}).then((response) => {
let link = window.URL.createObjectURL(blob)
link.download = 'Results.pdf'
link.click()
})
Or you can use window.open method:
axios.post(`order-results/${id}/export-pdf`, {
data,
responseType: 'blob'
}).then((response) => {
window.open(URL.createObjectURL(response.data));
})
You're getting empty PDF 'cause no data is passed to the server. You can try passing data using data object like this
axios.post(`order-results/${id}/export-pdf`, {
data: {
firstName: 'Fred'
},
responseType: 'arraybuffer'
}).then((response) => {
console.log(response)
let blob = new Blob([response.data], { type: 'application/pdf' } ),
url = window.URL.createObjectURL(blob)
window.open(url); // Mostly the same, I was just experimenting with different approaches, tried link.click, iframe and other solutions
});
By the way I gotta thank you so much for showing me the hint in order to download pdf from response. Thank ya :)
var dates = {
fromDate: 20/5/2017,
toDate: 25/5/2017
}
The way in which I have used is,
axios({
method:'post',
url:'/reports/interval-dates',
responseType:'arraybuffer',
data: dates
})
.then(function(response) {
let blob = new Blob([response.data], { type: 'application/pdf' } );
let link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = 'Report.pdf';
link.click();
});

Categories

Resources