Skip to content

Instantly share code, notes, and snippets.

@senthilmpro
Last active April 27, 2024 03:37
Show Gist options
  • Star 21 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save senthilmpro/072f5e69bdef4baffc8442c7e696f4eb to your computer and use it in GitHub Desktop.
Save senthilmpro/072f5e69bdef4baffc8442c7e696f4eb to your computer and use it in GitHub Desktop.
Download File using axios : Node.js program
'use strict'
const Fs = require('fs')
const Path = require('path')
const Axios = require('axios')
async function downloadImage () {
const url = 'https://unsplash.com/photos/AaEQmoufHLk/download?force=true'
const path = Path.resolve(__dirname, 'images', 'code1.jpg')
// axios image download with response type "stream"
const response = await Axios({
method: 'GET',
url: url,
responseType: 'stream'
})
// pipe the result stream into a file on disc
response.data.pipe(Fs.createWriteStream(path))
// return a promise and resolve when download finishes
return new Promise((resolve, reject) => {
response.data.on('end', () => {
resolve()
})
response.data.on('error', () => {
reject()
})
})
}
async function Main(){
const data = await downloadImage();
console.log("DATA ", data);
}
Main();
@MartinMuzatko
Copy link

if you use await, don't use then

@senthilmpro
Copy link
Author

Sure. Updated the code.

@intsdev
Copy link

intsdev commented Jun 22, 2020

Isn't it better to call resolve() at the end of writing to disk?

const writer = Fs.createWriteStream(path)
...
response.data.pipe(writer)
...
return new Promise((resolve, reject) => {
    writer.on('finish', resolve)
    writer.on('error', reject)
  })

Copy link

ghost commented Jul 28, 2020

Isn't it better to call resolve() at the end of writing to disk?

const writer = Fs.createWriteStream(path)
...
response.data.pipe(writer)
...
return new Promise((resolve, reject) => {
    writer.on('finish', resolve)
    writer.on('error', reject)
  })

I agree with you. In the shown example the promise is resolved when the file finishes download.
But in your example the promise is resolved when BOTH

  • the file finished download AND

  • the file is successfully written to the new path on disk

@onursagir
Copy link

If u don't want to use streams you can set responseType: "arraybuffer" like this

const res = await axios.get(url, { responseType: "arraybuffer" });
await fs.promises.writeFile(downloadDestination, res.data);

@dimawebmaker
Copy link

Thx friend. This snippet rly helped me :)

@csprocket777
Copy link

Is it possible to do this all in memory instead of writing a file?

@senthilmpro
Copy link
Author

Is it possible to do this all in memory instead of writing a file?

instead of doing a response.pipe into a file..
use a library like https://github.com/paulja/memory-streams-js and write your streams into memory.

@rcastera
Copy link

rcastera commented Nov 4, 2021

Isn't it better to call resolve() at the end of writing to disk?

const writer = Fs.createWriteStream(path)
...
response.data.pipe(writer)
...
return new Promise((resolve, reject) => {
    writer.on('finish', resolve)
    writer.on('error', reject)
  })

This was great! I've modified this a little. Here is my module:

const fs = require('fs')
const axios = require('axios')
const _ = require('underscore')

module.exports = {
    downloadFile: async function (src, dest) {
        // axios download with response type "stream"
        return await axios({
            method: 'GET',
            url: src,
            responseType: 'stream'
        })
        .then(function (response) {
            if (response && response.status === 200 && !_(response.data).isUndefined() && !_(response.data).isNull()) {
                let writer = fs.createWriteStream(dest)

                // pipe the result stream into a file on disc
                response.data.pipe(writer)

                // return a promise and resolve when download finishes
                return new Promise((resolve, reject) => {
                    writer.on('finish', () => {
                        resolve(true)
                    })

                    writer.on('error', (error) => {
                        reject(error)
                    })
                })
            }
        })
        .catch(function (e) {
            throw new Error(e)
        });
    }
}

Usage:

const downloader = require('../utils/download')
...

downloader.downloadFile(src, dest)
        .then(function (result) {
            if (result === true) {
                ...
            }
        })
        .catch(function (e) {
            console.log(e)
        });

@GomorraZPG
Copy link

Dzięki wielkie mam nadziej ze za działa

@markg85
Copy link

markg85 commented Jul 26, 2023

This got me going - and annoyed - by nodejs.
I wanted to try the fs promises version of fs to handle a download. Turns out that it's quite different and even feels c-like.

Here's a download function that uses fs promises and axios as http handler:

const axios = require('axios');
const fs = require('fs/promises');

const downloadFile = async (url, destination) => {
    let file = null;
    try {
        console.log(`Starting file download with url ${url}`)
        const response = await axios({
            method: 'GET',
            url: url,
            responseType: 'stream'
          })

        file = await fs.open(destination, 'w')
        const writer = file.createWriteStream()
        response.data.pipe(writer)

        await new Promise((resolve, reject) => {
            writer.on('finish', async () => {
                console.log(`Completed download with url ${url}`)
                resolve()
            })
            writer.on('error', reject)
          })
    } catch (error) {
        throw new Error(error);
    } finally {
        file?.close()
    }
}

Frankly, it's ugly. I thought promises were to make things easier and prettier (and they often are!), but the case of downloading a file (specially the writer object that you need to promisify still) just makes it look messy.

Note the use of finally to close the file handle. The ? part in file?.close() handles the error case neatly.
Also note that this means you must not return within the try block else the finally won't be called.

Call with something like:
await downloadFile("https://whatever/url/to/file", "/destination/file");

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment