Source:  Twitter logo

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:

  • returns ReadableStream
  • Is NOT supported by IE11
  • Does NOT allow for intercepting requests
  • The status of a response relates to the request itself, not the HTTP status
    • This means that the only way to receive an error would be to have something go wrong with the stream ending prematurely
    • This definitely won't work for me since I have custom error-handling related to user permissions

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

  • Is it possible to have a ReadableStream in Axios same as fetch?
  • Is streaming in Axios only possible when assuming that it will be supported by Node in a server-side only setting?
    • Sites like this appear to say that using responseType: 'stream' isn't something that can be done in the browser, only with Node.js using fs
  • Is it possible to use fetch or something else in conjunction with Axios?

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.

8 users liked answer #0dislike answer #08
Torc profile pic
Torc

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();
  })
0 users liked answer #1dislike answer #10
whoami profile pic
whoami

Copyright © 2022 QueryThreads

All content on Query Threads is licensed under the Creative Commons Attribution-ShareAlike 3.0 license (CC BY-SA 3.0).