Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stream response to file using Fetch API and fs.createWriteStream

I'm creating an Electron application and I want to stream an image to a file (so basically download it).

I want to use the native Fetch API because the request module would be a big overhead.

But there is no pipe method on the response, so I can't do something like

fetch('https://imageurl.jpg')
    .then(response => response.pipe(fs.createWriteStream('image.jpg')));

So how can I combine fetch and fs.createWriteStream?

like image 395
Tamás Avatar asked Jun 21 '17 10:06

Tamás


People also ask

What is FS createWriteStream?

Writable: streams to which we can write data. For example, fs. createWriteStream() lets us write data to a file using streams. Readable: streams from which data can be read. For example: fs.

What is response in Fetch?

The Response interface of the Fetch API represents the response to a request. You can create a new Response object using the Response() constructor, but you are more likely to encounter a Response object being returned as the result of another API operation—for example, a service worker FetchEvent.

How do I fetch a file in node JS?

Downloading a file using node js can be done using inbuilt packages or with third party libraries. GET method is used on HTTPS to fetch the file which is to be downloaded. createWriteStream() is a method that is used to create a writable stream and receives only one argument, the location where the file is to be saved.


2 Answers

I got it working. I made a function which transforms the response into a readable stream.

const responseToReadable = response => {
    const reader = response.body.getReader();
    const rs = new Readable();
    rs._read = async () => {
        const result = await reader.read();
        if(!result.done){
            rs.push(Buffer.from(result.value));
        }else{
            rs.push(null);
            return;
        }
    };
    return rs;
};

So with it, I can do

fetch('https://imageurl.jpg')
    .then(response => responseToReadable(response).pipe(fs.createWriteStream('image.jpg')));
like image 165
Tamás Avatar answered Nov 15 '22 16:11

Tamás


Fetch is not really able to work with nodejs Streams out of the box, because the Stream API in the browser differs from the one nodejs provides, i.e. you can not pipe a browser stream into a nodejs stream or vice versa.

The electron-fetch module seems to solve that for you. Or you can look at this answer: https://stackoverflow.com/a/32545850/2016129 to have a way of downloading files without the need of nodeIntegration.

There is also needle, a smaller alternative to the bulkier request, which of course supports Streams.

like image 23
RoyalBingBong Avatar answered Nov 15 '22 14:11

RoyalBingBong