Source: transport.js

import urlEncoder from 'encodeurl';

/**
 * Handles fetching.
 *
 * This class should not be used directly, but should instead be obtained
 * from {@link ServiceDescriptor#resourcefulEndpoint} or {@link ServiceDescriptor#businessEndpoint}
 *
 * @param {TransportDefaults?} options - The options to use with all fetch requests
 * @param {string?} encodeUri - Indicate whether to encode request URIs generated. Defaults `false`
 *
 * @property {TransportDefaults?} defaults - Stored from the initial 'options' parameter merged with the standard defaults
 *
 * @example
 * import Transport from '@pikselpalette/sequoia-js-client-sdk/lib/transport';
 *
 * const transport = new Transport({method: 'POST'});
 * transport.fetchWithDefaults('someurl').then((response) => console.log(response);
 *
 */
class Transport {
  /**
   * @typedef {Object} TransportDefaults
   *
   * Default fetch options to send with all `fetch` requests.
   *
   * @see {@link https://github.github.io/fetch/#options}
   */

  constructor(fetchOptions = {}, encodeUri = false) {
    this.defaults = Object.assign(
      {},
      {
        method: 'GET',
        mode: 'cors',
        headers: {
          'Content-Type': 'application/vnd.piksel+json',
          Accept: 'application/json'
        }
      },
      fetchOptions
    );
    this.encodeUri = encodeUri;
  }

  /**
   * Encodes the request url if `this.encodeUri` is true.
   *
   * @param {string} url - the url to potentially encode
   */
  encodeUrl(url) {
    if (this.encodeUri === true) {
      // use encodeUrl dep as it won't double-encode
      this.encodeUrl = u => urlEncoder(u);
      return urlEncoder(url);
    }
    this.encodeUrl = u => u;
    return url;
  }

  /**
   * Performs a {@link https://github.github.io/fetch/|fetch} with the default options from {@link Transport}
   *
   * @param {string} url - sequoia url
   * @param {object} options - [fetch options]{@link https://github.github.io/fetch/#options}
   *
   * @returns {Promise}
   */
  fetchWithDefaults(url, options = {}) {
    return fetch(
      this.encodeUrl(url),
      Object.assign({}, this.defaults, options)
    ).then((response) => {
      if (!response.ok) {
        return response.json().then(
          (responseBody) => {
            const error = new Error(responseBody.message);
            error.response = response;
            throw error;
          },
          () => {
            const error = new Error(response.statusText);
            error.response = response;
            throw error;
          }
        );
      }

      if (response.status === 204) {
        return {};
      }

      return response.json();
    });
  }

  /**
   * Performs an HTTP GET request
   *
   * @param {string} url - sequoia url
   * @param {object} options - [fetch options]{@link https://github.github.io/fetch/#options}
   *
   * @returns {Promise}
   */
  get(url, options = {}) {
    return this.fetchWithDefaults(url, options);
  }

  /**
   * Performs an HTTP POST request
   *
   * @param {string} url - sequoia url
   * @param {object} options - [fetch options]{@link https://github.github.io/fetch/#options}
   *
   * @returns {Promise}
   */
  post(url, options = {}) {
    return this.fetchWithDefaults(
      url,
      Object.assign({ method: 'POST' }, options)
    );
  }

  /**
   * Performs an HTTP PUT request
   *
   * @param {string} url - sequoia url
   * @param {object} options - [fetch options]{@link https://github.github.io/fetch/#options}
   *
   * @returns {Promise}
   */
  put(url, options = {}) {
    return this.fetchWithDefaults(
      url,
      Object.assign({ method: 'PUT' }, options)
    );
  }

  /**
   * Performs an HTTP DELETE request
   *
   * @param {string} url - sequoia url
   * @param {object} options - [fetch options]{@link https://github.github.io/fetch/#options}
   *
   * @returns {Promise}
   */
  destroy(url, options = {}) {
    return this.fetchWithDefaults(
      url,
      Object.assign({ method: 'DELETE' }, options)
    );
  }
}

export default Transport;