Source: utils/http/BackendRequest.js

import axios from 'axios';

/**
 * @typedef {object} BackendRequestOptions
 * @property url {string} the url, use {query} to add url query parameters
 * @property type {string} the request type (get, post etc.)
 * @property body {object?} a dictionary object for body parameters
 * @property query {object?} a dictionary object of query parameters
 * @property headers {object?} a dictionary object of additional request headers
 */

/**
 * Wrapper for standardized requests to the backend that do not throw an error
 * but instead stores the response / error as member variables.
 * @class
 */
class BackendRequest {
  /**
   * @constructor
   * @param options {BackendRequestOptions}
   */
  constructor(options) {
    const { url, type, body, query, headers, ...rest } = options;
    this.url = url;
    this.type = type.toLowerCase();
    this.body = body;
    this.query = query;
    this.response = null;
    this.error = null;
    this.headers = headers;
    this.extraOptions = rest;
  }

  /**
   * Send the request to the server and store
   * the response / error as member variables.
   *
   * @return {Promise<BackendRequest>}
   */
  async send() {
    try {
      const fn = axios[this.type];
      const args = [this.url];
      if (this.query) args.push({ params: this.query });
      if (this.body) args.push(this.body);

      const extraOptions = { ...this.extraOptions };

      if (this.headers) {
        extraOptions.headers = this.headers;
      }

      args.push(extraOptions);
      this.response = await fn.apply(axios, args);
    } catch (error) {
      this.response = error.response ?? null;
      this.error = error;
    }
    return this;
  }
}

const globalHooks = new Set();

/**
 *
 * @param fn
 */
export const registerGlobalRequestHook = (fn) => {
  globalHooks.add(fn);
};

/**
 * Sends an HTTP request to the backend but does not throw on error
 * but instead returns an object that contains a response and error property.
 *
 * @param options {BackendRequestOptions}
 * @return {Promise<BackendRequest>}
 */
export const request = async (options) => {
  const req = await new BackendRequest(options).send();
  globalHooks.forEach((fn) => fn(req));
  return req;
};