Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I download and save a file using the Fetch API? (Node.js)

I have the url to a possibly large (100+ Mb) file, how do I save it in a local directory using fetch?

I looked around but there don't seem to be a lot of resources/tutorials on how to do this.

Thank you!

like image 530
Gloomy Avatar asked Jun 03 '16 12:06

Gloomy


People also ask

How do I save a file in node JS?

writeFile("/tmp/test", message, function (err) { if (err) { return console. log(err); } console. log("The file was saved!"); }); }); Hope this works for you.

Can I use fetch API in node JS?

Fetch is already available as an experimental feature in Node v17. If you're interested in trying it out before the main release, you'll need to first download and upgrade your Node. js version to 17.5.

How do you get data from an API using Fetch?

Approach: First make the necessary JavaScript file, HTML file and CSS file. Then store the API URL in a variable (here api_url). Define a async function (here getapi()) and pass api_url in that function. Define a constant response and store the fetched data by await fetch() method.

How do you make a node js file downloadable?

Create Controller for download File It exports 2 functions: getListFiles() : read all files in uploads folder, return list of files' informationn (name, url) download() : receives file name as input parameter, then uses Express res. download API to transfer the file at path (directory + file name) as an 'attachment'.


3 Answers

Using the Fetch API you could write a function that could download from a URL like this:

const downloadFile = (async (url, path) => {   const res = await fetch(url);   const fileStream = fs.createWriteStream(path);   await new Promise((resolve, reject) => {       res.body.pipe(fileStream);       res.body.on("error", reject);       fileStream.on("finish", resolve);     }); }); 
like image 79
code_wrangler Avatar answered Sep 23 '22 19:09

code_wrangler


If you want to avoid explicitly making a Promise like in the other very fine answer, and are ok with building a buffer of the entire 100+ MB file, then you could do something simpler:

const fetch = require('node-fetch');
const {writeFile} = require('fs');
const {promisify} = require('util');
const writeFilePromise = promisify(writeFile);

function downloadFile(url, outputPath) {
  return fetch(url)
      .then(x => x.arrayBuffer())
      .then(x => writeFilePromise(outputPath, Buffer.from(x)));
}

But the other answer will be more memory-efficient since it's piping the received data stream directly into a file without accumulating all of it in a Buffer.

like image 20
Ahmed Fasih Avatar answered Sep 21 '22 19:09

Ahmed Fasih


const {createWriteStream} = require('fs');
const {pipeline} = require('stream/promises');
const fetch = require('node-fetch');

const downloadFile = async (url, path) => pipeline(
    (await fetch(url)).body,
    createWriteStream(path)
);
like image 35
Ihor Sakailiuk Avatar answered Sep 23 '22 19:09

Ihor Sakailiuk