services/requests.mjs

import Service from '@mirlo/base/service';

/**
 * Proxy handler for the components state.
 * @typedef {Object} RequestsMethodEnum
 * @property {string} POST - Represents a POST requests.
 * @property {string} GET - Represents a GET requests.
 * @private
 */

/**
 * Enum with the available HTTP Requests methods.
 * @type {RequestsMethodEnum}
 * @const
 * @private
 */
export const HTTP_METHOD = {
  POST: 'POST',
  GET: 'GET',
};

/**
 * Class to implement HTTP Requests as a Service.
 * @extends Service
 * @hideconstructor
 */
class RequestsService extends Service {
  #cache = {};

  /**
   * The error messages.
   * @type {Object}
   * @property {string} e200 - The message for business logic error.
   */
  MESSAGES = {
    e200: '200: Invalid server result!',
  };

  /**
   * Get the HTTP Requests headers.
   * @param {Object} custom_headers - The http headers.
   * @returns {Object}
   */
  getHeaders(custom_headers) {
    return custom_headers;
  }

  /**
   * Fetch JSON data.
   * @param {string} url - The URL.
   * @param {Object} data - The payload.
   * @param {RequestsMethodEnum} method - The HTTP Request method.
   * @returns {Promise}
   */
  async queryJSON(url, data, method = HTTP_METHOD.POST, cache_name) {
    const use_cache = typeof cache_name !== 'undefined';
    let prom_response;
    if (use_cache && Object.hasOwn(this.#cache, cache_name)) {
      prom_response = this.#cache[cache_name];
    } else {
      const query_options = {
        method: method,
        mode: 'same-origin',
        cache: 'no-cache',
        credentials: 'same-origin',
        headers: this.getHeaders({
          'Content-Type': 'application/json',
        }),
        redirect: 'follow',
        referrerPolicy: 'same-origin',
      };
      if (typeof data !== 'undefined') {
        query_options.body = JSON.stringify(data);
      }

      if (use_cache) {
        prom_response = this.#cache[cache_name] = fetch(url, query_options);
      } else {
        prom_response = fetch(url, query_options);
      }
    }

    const response = await prom_response;
    const result = await response.clone().json();
    if (this.checkServerResult(result)) {
      return result;
    }
    throw Error(this.MESSAGES.e200);
  }

  /**
   * POST Fetch JSON data.
   * @param {string} url - The URL.
   * @param {Object} data - The payload.
   * @param {string} cache_name - The cache name.
   * @returns {Promise}
   */
  postJSON(url, data, cache_name) {
    return this.queryJSON(url, data, HTTP_METHOD.POST, cache_name);
  }

  /**
   *
   * @param {string} url - The URL.
   * @param {string} cache_name - The cache name.
   * @returns {Promise}
   */
  getJSON(url, cache_name) {
    return this.queryJSON(url, undefined, HTTP_METHOD.GET, cache_name);
  }

  /**
   * POST Fetch data.
   * @param {string} url - The URL.
   * @param {Object} data - The payload.
   * @param {string} cache - The cache store name.
   * @returns {Any}
   */
  async post(url, data, cache = 'default') {
    let fdata = false;
    if (typeof data === 'object') {
      fdata = new URLSearchParams();
      for (const k in data) {
        fdata.append(k, data[k]);
      }
    } else if (typeof data === 'string') {
      fdata = data;
    }
    const response = await fetch(url, {
      method: 'POST',
      mode: 'same-origin',
      cache: cache,
      credentials: 'same-origin',
      headers: this.getHeaders({
        'Content-Type': 'application/x-www-form-urlencoded',
      }),
      redirect: 'follow',
      referrerPolicy: 'same-origin',
      body: fdata,
    });
    const result = response.json();
    if (this.checkServerResult(result)) {
      return result;
    }
    throw Error(this.MESSAGES.e200);
  }

  /**
   * GET Fetch data.
   * @param {string} url
   * @param {string} cache
   * @returns {Any}
   */
  async get(url, cache = 'default') {
    const response = await fetch(url, {
      method: 'GET',
      mode: 'same-origin',
      cache: cache,
      credentials: 'same-origin',
      headers: this.getHeaders(),
      redirect: 'follow',
      referrerPolicy: 'same-origin',
    });
    return response.blob();
  }

  /**
   * Check if the response of the requests is a valid response.
   * @param {Object} data - The response data.
   * @returns {boolean}
   */
  checkServerResult(data) {
    if (!data || typeof data === 'undefined') {
      return false;
    }
    return true;
  }
}

export default RequestsService;