Source: lib/Client/ExternalClients.js

import axios from "axios";

class ExternalRESTClients {
  /**
   * The RESTClient is a singleton class that handles the connection and data exchange from the back-end
   * REST API.
   */
  constructor() {
    if (ExternalRESTClients._instance) {
      return ExternalRESTClients._instance;
    }
    ExternalRESTClients._instance = this;
    this.baseUrl = import.meta.env.VITE_API_ENDPOINT;
    this.headers = {
      Accept: "application/x-bibtex",
    };
    this.pmidBaseURL =
      "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=pubmed&retmode=json&id=";
    this.tessBaseURL = "https://tess.elixir-europe.org/materials.json?q=";
    this.orcidBaseURL = "https://pub.orcid.org/v2.0/";
    this.rorOrganisationsBaseURL =
      "https://api.ror.org/v2/organizations?query=";
  }

  async getDOI(doi) {
    // Point this to your Rails backend route instead of dx.doi.org.
    // Ensure the route matches your setup (e.g., it might be '/api/zenodo' or '/zenodo')
    let user = JSON.parse(localStorage.getItem("user"));
    let token;
    if (user) {
      token = user.credentials.token;
    }
    const targetUrl = `${this.baseUrl}/zenodo?doi=${encodeURIComponent(doi)}`;
    const request = {
      url: targetUrl,
      headers: {
        Accept: "application/json",
        Authorization: `Bearer ${token}`,
      },
    };

    let response = await this.executeQuery(request);
    return response.data;
  }

  async getPMID(id) {
    const request = {
      url: this.pmidBaseURL + id,
      headers: {
        Accept: "application/json",
      },
    };
    let response = await this.executeQuery(request);
    return response.data;
  }

  async getTessRecords(string) {
    const request = {
      url: this.tessBaseURL + string,
      headers: this.headers,
    };
    let response = await this.executeQuery(request);
    return response.data;
  }

  async getOrcidUser(user) {
    this.headers["Accept"] = "application/orcid+json";
    const request = {
      url: this.orcidBaseURL + user,
      headers: this.headers,
    };
    let response = await this.executeQuery(request);
    this.headers["Accept"] = "application/x-bibtex";
    return response.data;
  }

  async getROROrganisation(organisation) {
    let localHeaders = this.headers;
    localHeaders["Accept"] = "application/json";
    const request = {
      url: this.rorOrganisationsBaseURL + organisation,
      headers: localHeaders,
    };
    let response = await this.executeQuery(request);
    return response.data;
  }

  /**
   * Trigger the given query with Axios
   * @param query
   * @returns {Promise<*>}
   */
  async executeQuery(query) {
    try {
      const response = await axios.get(query.url, { headers: query.headers });
      // Check if we got HTML instead of JSON
      const contentType = response.headers["content-type"] || "";
      if (contentType.includes("text/html")) {
        throw new Error(
          "Expected JSON but received HTML (Website instead of API)",
        );
      }
      // Check if the data is empty or generic error-like HTML
      if (!response.data || response.data.length === 0) {
        throw new Error("No data returned from the source");
      }
      return response;
    } catch (e) {
      // This will now catch both Network/CORS errors AND the manual HTML error above
      return {
        data: {
          error: e.message || e,
          isError: true,
        },
      };
    }
  }
}

export default ExternalRESTClients;