2

Question in brief

From within a JavaScript web application how can I have a user's browser download a large (on the order of gigabytes), dynamically generated file from a RESTful endpoint which requires the setting of headers?

Question at length

From within a JavaScript web application I need to provide users with the ability to download a potentially large (~GBs), dynamically generated file in one of several formats (eg text/flatfile, application/vnd.ms-excel, and others) from a RESTful API. The desired format is indicated in the header of the request. For example, to download a fasta format version of the file:

curl -s -H 'accept:text/fasta' 'https://.../api/download?query=human'

The back end will run the query, retrieve the results, and return a file in the fasta format. An issue arises when I want the front end application to provide a download link to the user. Disregarding the need for setting headers I can create a download link like so:

const link = document.createElement('a');
link.href = "https://.../api/download?query=human";
link.setAttribute('download', 'download');
document.body.appendChild(link);
link.click();

or equivalently as HTML:

<a download href="https://.../api/download?query=human">
    download human fasta
</a>

However, as far as I know, I don't have a means of setting the header to specify the format. I could make a request within the app itself:

axios.get(
    'https://.../api/download?query=human',
    {
      headers: {
        Accept: 'text/fasta',
      },
    }
  )
  .then(response => {
    // provide response.data to the client as a download link
  });

However, I can see several problems with this:

  1. This will fill up the user's browser's memory (and these can be large downloads)
  2. There will be no indication of progress (eg 50% done)
  3. It will be tied to the web app's browser tab as it's not a separate download process. If this is closed the download cancels.

Potential front end solution

Problems 1 and 2 could potentially be solved with the Streams API but problem 3 would still exist.

Potential back end solution

As the back end team who manage the API are open to modifications a potential (and less RESTful way) solution is to request a particular file format is by using a format parameter in the url. Then to access the fasta format of the "human" query I can do:

<a download href="https://.../api/download?query=human&format=flatfile">
    download human fasta
</a>

Do other solutions or approaches exist?

Danyule
  • 331
  • 1
  • 6
  • Just out of curiosity. Why would you say that sending a parameter is a "less RESTful" way? – gforce301 Nov 22 '19 at 19:52
  • It was explained to me by the back end that the URL should map uniquely to a single resource - the data for the file. The formats are just different views of that data. Looking into it it seems putting the format as a parameter in the URL [acts as a filter and is still considered RESTful because it "returns a modification of the found resource rather than homing in on which resource we want"](https://stackoverflow.com/a/17999251/1584532) – Danyule Nov 23 '19 at 11:19

0 Answers0