Download files using url in javascript - javascript

I have multiple url's, pointing to different files. I want to be able to download them just by using the url string automatically with Javascript code, instead of manually going to the link and downloading them.
I have searched a lot of other answers on stackoverflow, few suggest creating an anchor tag in document body, but I am doing everything on backend not creating an index.html
edit: I am using next where for an api end point I am getting post requests, each which contains URL for a file which I have to download.
This is how I expect my POST request to come:
I want to be able to do something like this (in nextjs):
export default async function handler (req, res) {
if(req.method === "POST") {
let path = "./downloads/file"
await download(req.body.url, path)
}
}
Is the download function possible, if so please help me with the implementation or provide any helpful packages to do the same.

You can use HTTP clients like Axios. It makes it easy to send async HTTP requests to REST endpoints and perform CRUD operations.
You can refer to the snippet below that I have used in my previous projects for file downloads. I guess this is what you are looking for:
const fs = require('fs')
const Path = require('path')
const axios = require('axios')
const crypto = require('crypto')
async function downloadFile(url) {
const uuid = crypto.randomUUID()
const path = Path.resolve("./utils", "uploads", uuid)
const writer = fs.createWriteStream(path)
const response = await axios({
url,
method: 'GET',
responseType: 'stream'
})
response.data.pipe(writer)
return new Promise((resolve, reject) => {
writer.on('error', reject)
response.data.on('end', () => {
resolve(uuid)
})
})
}
Hope this helps, and don't forget to check out their documentation. Here is the
link.

Download by get request
const downloadFabricFormat = async () => {
try{
await axios({
url: '/api/fabric/fabric_excel_format/',
method: 'GET',
responseType: 'blob',
}).then((response) => {
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', 'Fabric Excel Format.xlsx');
document.body.appendChild(link);
link.click();
});
} catch(error){
console.log(error)
}
};
Download by post request
const postFabricQRCode = async (values) => {
try{
await axios({
url: `/api/qr/code/download/`,
method: 'POST',
responseType: 'blob',
data: values,
}).then((response) => {
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', 'fabric-qr-code.pdf');
document.body.appendChild(link);
link.click();
});
} catch(error){
console.log(error)
}
};
Change file type here. link.setAttribute('download', 'Fabric Excel Format.xlsx');
Also manage your back-end yourself.

Related

problem in downloading zip folder from lambda/node/express api to reactjs app - Window can not open the folder

I run into unknown issue as described below,
I have node/express api which returns data as shown below,
...
...
const zip = new AdmZip();
// Define zip file name
const timedate = this.getDateTime();
let downloadName = `myZip-${timedate}.zip`;
const data = zip.toBuffer();
const fileType = 'application/zip';
res.writeHead(200, {
'Content-Disposition': `attachment; filename="${downloadName}"`,
'Content-Type': fileType,
})
return res.end(data);
ReactApp
const ReadResponse = async (response: any) => {
const blob = await response.blob();
/**
I can confirm above blob object contains data as shown below
size:13258
type:"application/zip"
[[Prototype]]:Blob
**/
const a = document.createElement('a');
document.body.appendChild(a);
const url = window.URL.createObjectURL(blob);
a.href = url;
const filename = "myZip.zip";
a.download = filename;
a.click();
setTimeout(() => {
window.URL.revokeObjectURL(url);
document.body.removeChild(a);
}, 0)
};
hitting localhost:2000/api/download, it downloads the zip folder and when I open it I can see the content in it.
But the same code when goes to lambda function, hitting whateverdomain/api/download api returns blob response, I can download the zip folder as well but when try to open it, it throws
windows can't open the folder
Tried with different different approaches but can't seem to find reason what's wrong ?

How to mock axios zip download call, using axios-mock-adaptor?

I have a code which is downloading the zip as arraybuffer and subsequently uses admZip to get the files inside. I am trying to unit test a method which calls this method and got stuck around mocking the zip download call.
The code is -
export const downloadZip = async (zipUrl: string): Promise<Buffer> => {
const axiosInstance = axios.create({ headers: getHeaders() });
const body = await axiosInstance.get(zipUrl, {
responseType: 'arraybuffer'
});
return body.data
}
Does anyone have any prior experience on this and can help?
This may help.
const mock = new MockAdapter(axiosInstance);
mock.onGet("https://zip_url").reply(200, {data: "zipData"});
await expect(AxiosClient().get("https://zip_url")).tobe({data: "zipData"})

How to download .zip file that i recieve from a HTTP response (axios PUT request)

So the API's response contains data property which should contain the .zip file that i need. Its written in a format i do not understand.
The format:
I tried using .blob() as referenced in similar questions here on Stackoverflow, but it doesn't seem to work.
The ideal solution is this: when client presses the button, he should be prompted to download said .zip file (the one from the HTTP response) locally. I'm using axios and the request type is PUT.
My code example so far:
const exportCards = () => {
axios
.put(url, {
ids: ids,
})
.then((res) => {
return res.data.blob();
})
.then((blob) => {
var file = window.URL.createObjectURL(blob);
window.location.assign(file);
})
.catch((e) => console.log(e));
};
What I wanted:
send files of any formats from the back-end to the front-end
My tools:
axios, express, saveAs
The problem I faced with:
Unable to download zip file using axios
https://github.com/eligrey/FileSaver.js/issues/156
https://github.com/axios/axios/issues/448
Nothing helped me, probably because I did something wrong. But here is a simple and quick solution that I came up with:
//BE
const filename = "my-file-name.json";
const zip = new AdmZip();
zip.addFile(filename, body);
const content = zip.toBuffer();
res.set({
"Content-Length": Buffer.byteLength(content), //I'm not sure if this is necessary, but it's better to let it be :-)
"Content-Type": "text/plain",
"Content-Disposition": `attachment; filename=${filename}.${format}`,
});
res.status(200).send(content.toString("hex")); //my solution to the problem
//FE
const { headers, data } = await axios.post(myEndpoint);
const headerLine = headers["content-disposition"];
const filename = headerLine.replace(/[\w; ]+filename=/g, "");
const content = Buffer.from(data, "hex");
const blob = new Blob([content], { type: "application/zip" });
saveAs(blob, filename); //file-saver npm package
a tag has download attribute, in .then you can try something like that
const url = new Blob([response.data],{type:'application/zip'});
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', 'file.zip'); //set download attribute to link
document.body.appendChild(link);
link.click(); // this will download file.zip
I would suggest fetch over axios in concern of zip file because sometimes the response in axios request is not accurate and you might fall into currupted zip file while downloading, the best might be using a package called file-saver and fetch. I am posting this answer to help the developers to grab the concept only, the code is tested in React.
package file-saver:https://www.npmjs.com/package/file-saver
Now make any function according to your choice in react, I am assuming functional component so will write method according to functional component syntax.
note before using saveAs function you need to import from the installed package file-saver.
import { saveAs } from 'file-saver';
const downloadZipFileFromLaravel=()=>{
fetch(`your url`)
.then(res => res.blob())
.then(blob => saveAs(blob, 'Auto Photos.zip')) // saveAs is a function from the file-saver package.
.catch((err) => {
console.log(err.message);
});
}
at the end you need to connect the function with a button with onClick.
example
<button onClick={()=>downloadZipFileFromLaravel()}> </button>
Note: usage of file saver in pure javascript, you can check this:
How to use filesaver.js
For more information you can see the below discussion:
Reference: https://github.com/eligrey/FileSaver.js/issues/156
Your problem is that you didn't explicitly specify the response type in your PUT request. This should work:
const exportCards = () => {
axios
.put(url, {
ids: ids,
}, {
responseType: 'blob'
})
.then((res) => { // Now 'res.data' is Blob, not a string
var file = window.URL.createObjectURL(res.data);
window.location.assign(file);
})
.catch((e) => console.log(e));
};

javascript error when downloading pdf file (blob)

I am using this approach for downloading a pdf file from server (laravel 8 (api sanctum) + vue 3)
In the vue component I have this function that downloads the file
const onDownloadDocument = (id) => {
axios.post('/api/document/download', {id: id},{
responseType: 'blob'
}).then(response => {
let filename = response.headers['content-disposition'].split('filename=')[1]
dLink.value.href = window.URL.createObjectURL(response.data)
dLink.value.setAttribute('download',filename)
dLink.value.click()
}).catch(error => {
console.log(error)
})
where dLink is a link ref
const dLink = ref(null)
in template:
<a ref="dLink"/>
It works this approach until today.... after I updated the project (composer update and npm update)
Now when click to download the file (call the onDownloadDocument function) I get an error:
contract.js:1049 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'responseType')
Any idea why ?
The api backend return the file blob
return Storage::download($document->filename);
First you need to create a blob and put your response in it,
And as I said in my comment you don't need to attach to a real anchor tag, you can just create an element, attach it to the body, simulate the click and remove it immediately
const blob = new Blob([response], {type: 'application/pdf'})
if (window.navigator['msSaveOrOpenBlob']) {
window.navigator['msSaveBlob'](blob, filename)
}
else {
const elem = window.document.createElement('a')
elem.href = window.URL.createObjectURL(blob)
elem.download = filename
document.body.appendChild(elem)
elem.click()
document.body.removeChild(elem)
}
This worked for me, specify to axios that you are expecting a blog, and that's it:
axios({
url: 'http://localhost:5000/endpoint?',
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();
});

Push Data Into Array in State Array In Reactjs

Hello All I hope All Are Doing Well
I have A issue I am uploading multiple images in Cloudinary via ReactJs
Here Is Input Field
<input
type="file"
className="form-control"
required
onChange={(e) => setImages(e.target.files)}
multiple
/>
OnChange I'm storing all files on a state given below
const [images, setImages] = useState([]);
Now I am looping the state and uploading each file to Cloudinary and extracting the URL of each Image code is given below
for (const file of images) {
async function upload() {
const formData = new FormData();
formData.append("file", file);
formData.append("upload_preset", "DummyPreset"); // Replace the preset name with your own
formData.append("api_key", "0300545648961"); // Replace API key with your own Cloudinary key
// Make an AJAX upload request using Axios (replace Cloudinary URL below with your own)
await axios
.post(
"https://api.cloudinary.com/v1_1/Dummycloud/image/upload",
formData,
{
headers: { "X-Requested-With": "XMLHttpRequest" },
}
)
.then((response) => {
const data = response.data;
const fileURL = data.secure_url; // You should store this URL for future references in your app
console.log(fileURL);
});
}
upload();
}
Here I'm able to extract each link As fileURL and consoled it
console.log(fileURL);
To See The Output Please click the Link it will redirects you to the image Outputimage
As You Can see all URLs Are Extracted Now I want to push All Extracted URLs into an Array And Wants to send them to Express Server where I'll store them into DB
Please Let Me Know How Store All URLs into a state array whenever any URL extracted it'll be stored into That array
Here's The Solution
Thanks For Contribution
var ImagesUrlArray = [];
for (const file of image) {
async function upload() {
const formData = new FormData();
formData.append("file", file);
formData.append("upload_preset", "DummyPreset"); // Replace the preset name with your own
formData.append("api_key", "0300545648961"); // Replace API key with your own Cloudinary key
// Make an AJAX upload request using Axios (replace Cloudinary URL below with your own)
await axios
.post(
"https://api.cloudinary.com/v1_1/Dummycloud/image/upload",
formData,
{
headers: { "X-Requested-With": "XMLHttpRequest" },
}
).then((response) => {
const data = response.data;
var fileURL = data.secure_url; // You should store this URL for future references in your app
ImagesUrlArray = [...ImagesUrlArray];
ImagesUrlArray.push(fileURL);
if (ImagesUrlArray.length === image.length) {
const res = axios
.post("http://localhost:5000/register", {
fullname: Data.fullname,
email: Data.email,
pass: Data.pass,
cpass: Data.cpass,
phone: Data.phone,
imagee: ImagesUrlArray,
})
.then((response) => response);
setdataa(res);
}
});
}
upload();
}
// this function returns a Promise
const uploadFile = (file) => {
const formData = new FormData();
formData.append(stuff);
return axios.post('some/path', formData).then(response => response.data.secure_url);
};
Promise.all(images.map(uploadFile)).then(fileURLs => storeFileURLs(fileURLs))

Categories

Resources