title: Download zip file being sent by server on client side?
body: <p>I have an API that downloads multiple files from AWS S3, creates a zip which is saved to disk, and sends that zip back to the client. The API works, but I have no idea how to handle the response / download the zip to disk on the client side.</p>
  
  <p>This is my API:</p>
  
  <pre><code>reports.get('/downloadMultipleReports/:fileKeys', async (req, res) =&gt; {
  
    var s3 = new AWS.S3();
    var archiver = require('archiver');
  
    const { promisify } = require('util');
  
    var str_array = req.params.fileKeys.split(',');
  
    console.log('str_array: ',str_array);
  
    for (var i = 0; i &lt; str_array.length; i++) {
  
      var filename = str_array[i].trim();
      var filename = str_array[i];
      var localFileName = './temp/' + filename.substring(filename.indexOf("/") + 1);
  
      console.log('FILE KEY &gt;&gt;&gt;&gt;&gt;&gt;  : ', filename);
  
      const params = { Bucket: config.reportBucket, Key: filename };
  
      const data = await (s3.getObject(params)).promise();
  
      const writeFile = promisify(fs.writeFile);
  
      await writeFile(localFileName, data.Body);
    }
  
      // create a file to stream archive data to.
      var output = fs.createWriteStream('reportFiles.zip');
      var archive = archiver('zip', {
        zlib: { level: 9 } // Sets the compression level.
      });
  
      // listen for all archive data to be written
      // 'close' event is fired only when a file descriptor is involved
      output.on('close', function() {
        console.log(archive.pointer() + ' total bytes');
        console.log('archiver has been finalized and the output file descriptor has closed.');
      });
  
      // This event is fired when the data source is drained no matter what was the data source.
      // It is not part of this library but rather from the NodeJS Stream API.
      // @see: https://nodejs.org/api/stream.html#stream_event_end
      output.on('end', function() {
        console.log('Data has been drained');
      });
  
      // good practice to catch warnings (ie stat failures and other non-blocking errors)
      archive.on('warning', function(err) {
        if (err.code === 'ENOENT') {
          // log warning
        } else {
          // throw error
          throw err;
        }
      });
  
      // good practice to catch this error explicitly
      archive.on('error', function(err) {
        throw err;
      });
  
      // pipe archive data to the file
      archive.pipe(output);
  
      // append files from a sub-directory, putting its contents at the root of archive
      archive.directory('./temp', false);
  
      // finalize the archive (ie we are done appending files but streams have to finish yet)
      // 'close', 'end' or 'finish' may be fired right after calling this method so register to them beforehand
      archive.finalize();
  
      output.on('finish', () =&gt; {
  
        console.log('Ding! - Zip is done!');
  
        const zipFilePath =  "./reportFiles.zip" // or any file format
  
        // res.setHeader('Content-Type', 'application/zip');
  
        fs.exists(zipFilePath, function(exists){
  
          if (exists) {     
            res.writeHead(200, {
              "Content-Type": "application/octet-stream",
              "Content-Disposition": "attachment; filename=" + "./reportFiles.zip"
            });
            fs.createReadStream(zipFilePath).pipe(res);
  
          } else {
            response.writeHead(400, {"Content-Type": "text/plain"});
            response.end("ERROR File does not exist");
          }
  
        });
      });
  
    return;
  });
  </code></pre>
  
  <p>And this is how I am calling the API / expecting to download the response:</p>
  
  <pre><code>  downloadMultipleReports(){
  
      var fileKeysString = this.state.awsFileKeys.toString();
      var newFileKeys = fileKeysString.replace(/ /g, '%20').replace(/\//g, '%2F');
  
      fetch(config.api.urlFor('downloadMultipleReports', { fileKeys: newFileKeys }))
      .then((response) =&gt; response.body())
  
      this.closeModal();
    }
  </code></pre>
  
  <p>How can I handle the response / download the zip to disk?</p>