vgteam / sequenceTubeMap

displays multiple genomic sequences in the form of a tube map
MIT License
180 stars 25 forks source link

Refactor requests to the API so that they could be computed locally instead #377

Closed adamnovak closed 8 months ago

adamnovak commented 11 months ago

To implement #367, we are going to need to set things up so that sometimes, when you click "Go", instead of making an API request to /getChunkedData, we instead call some local JS/WASM code which makes its own web requests and/or operates on local files exposed to the browser, and eventually produces the data needed to render the tube map.

To support this, we should refactor the client-side code so that the current code that calls /getChunkedData is just one possible implementation of an interface.

So, for this issue, we should define a JavaScript class to represent that interface, and another class inheriting from the first that implements it by making requests to the tube map API server. The interface should cover:

  1. Requesting the chunk data given the tracks, region, and other settings.
  2. Taking a File API file and turning it into a URL to put in a track or use as a BED (i.e. doing the upload in the current implementation).
  3. Getting the list of paths in a graph, given a graph URL (which might be a URL from step 2).
  4. Getting track information for a BED file by URL (which also might be a URL from step 2).

Then we should replace the existing API code with code to instantiate an instance of this class, and to make API calls through the current implementation of the interface.

adamnovak commented 10 months ago

This could look like taking existing calls to fetchAndParse with particular paths based on apiUrl, and changing them to be calls to a method of this new interface, and then passing an instance of the interface down in the React props instead of apiUrl.

So a call like:

const json = await fetchAndParse(`${this.props.apiUrl}/getFilenames`, {
        signal: this.cancelSignal, // (so we can cancel the fetch request if we will unmount component)
        method: "GET",
        headers: {
          "Content-Type": "application/json",
        },
      });

Would become something like:

const json = await this.props.api.getFilenames(this.cancelSignal);

Or with an argument:

const json = await this.props.api.getBedRegions({ bedFile }, this.cancelSignal);

We can send the arguments either always as an object, or for one-argument methods we could decide that we don't actually want the wrapping object and generate it inside the implementation if needed.

adamnovak commented 9 months ago

I think I forgot to list some of the things the client needs to cover; it needs to cover everything that we use the API URL for.

adamnovak commented 8 months ago

This has been fixed now.