Torc
Torc

Reputation: 1322

Download Response Data as Stream w/ Axios in React App

Issue

I need to download query results from an endpoint by streaming results to a CSV file. This is in an effort to support enormous ResultSets being sent through the browser at one time.

Is there a way to accomplish this using Axios in the context of a React App?

I have seen fetch() and know that it has the following characteristics:

Besides the ReadableStream response type, the rest of the characteristics listed are not permissible. I will need to support IE11 and allow for intercepting requests / reading the HTTP status to determine how to handle the traffic.

Example with fetch:

      // The promise returned by `fetch` rejects if the fetch was unable to make HTTP-request
      //  e.g. network problems, or there’s no such site.
      // Abnormal HTTP-statuses, such as 404 or 500 do not cause an error.
      const results = await fetch(`${URL}/data`, {
        method: 'post', // HTTP POST to send query to server
        headers: {
          Accept: 'application/json, text/plain, */*', // indicates which files we are able to understand
          'Content-Type': 'application/json', // indicates what the server actually sent
        },
        body: JSON.stringify(query), // server is expecting JSON
        credentials: 'include', // sends the JSESSIONID cookie with the address
      }).then(res => res.json()) // turn the ReadableStream response back into JSON
        .then((res) => {
          if (res.ok) {
            // boolean, true if the HTTP status code is 200-299.
            console.log('response.ok!');
          } else if (res.status === 401) {
            throw Error(`You are not authenticated. Please login.`);
          } else if (res.status === 403) {
            throw Error(`You are not authorized to access this data.`);
          } else {
            throw Error(`Request rejected with status ${res.status}`);
          }
        })
        .catch((error) => {
          // catches error case and if fetch itself rejects
          error.response = {
            status: 0,
            statusText:
              'Cannot connect. Please make sure you are connected to internet.',
          };
          throw error;
        });

      console.log(results);

Example with axios (not streaming)

Axios instance

import ...
const Api = axios.create({
  baseURL: `${URL}`,
  withCredentials: true,
});

// attach interceptors to requests and responses
// these are defined elsewhere and imported
Api.interceptors.request.use((request) => requestHandler(request));
Api.interceptors.response.use((response) => successHandler(response), (error) => errorHandler(error));

export default Api;

Axios request

const query = {"selections":{"TABLE_A":["COLUMN1"]},"filters":[{"predicates":[]}],"joins":[],"sorts":[],"limit":100,"offset":0}
const response = await Api.post('/data', query);
// further transformations to response to get formatted csv results required

Questions about Axios

Upvotes: 12

Views: 43438

Answers (2)

whoami
whoami

Reputation: 1

If you just need to download a file, using blob in the responseType options is definitely okay.

axios.post(url, param, 
  { header: {...}, responseType: 'blob' }
)
 .then(res => {
      const link = document.createElement('a');
      link.href = URL.createObjectURL(res);
      link.click();
  })

Upvotes: -1

Torc
Torc

Reputation: 1322

Streaming a response from the browser is not currently supported :

https://github.com/axios/axios/issues/479

Since we're dealing with XMLHttpRequests in the browser, Axios is limited to the specification set by whatwg. :

Specifically, these are the only supported types :

enum XMLHttpRequestResponseType {
  "",
  "arraybuffer",
  "blob",
  "document",
  "json",
  "text"
};

stream is accepted when setting a responseType in axios, but this is misleading. The adapter is going to be xhr.js implicitly since we are using the browser which relies on XMLHttpRequests. HttpRequests are made on the server-side and will allow axios to use the http.js adapter. THEN you can use stream as a ResponseType with Node.js.

Using the fetch API seems to be the only solution with a ReadableStream as a response body type.

Upvotes: 15

Related Questions