Source: app/actions/resources/apiActions/apiRequest.js

/* global WP_DEFINE_DEVELOPMENT, WP_DEFINE_IS_NODE, WP_DEFINE_FORCE_FAIL_ON_SERVER_AUTH_GATEWAY */
import createAction from 'redux-actions/lib/createAction';
import { getValue } from '../../../util/injector';

/**
 * This module contains actions to perform basic api requests
 * @module apiRequest
 * @category api-calls
 * @tutorial basic-api-requests
 */

/**
 * Simple wrapper action to execute a gateway request. Will dispatch an async action (action with
 * promise on payload) with additional information about the API call on the meta property.
 * @function apiRequest
 * @param {string} method The request method to use ("get", "post", etc..)
 * @param {string} actionType The 'type' property of the dispatched action is set to this value
 * @param {string} gatewayType The type of gateway to use. These should be one of the strings
 * defined in _Injectables.js_
 * @param {string} path The path to the endpoint to request
 * @param {object} [data=null] Object with data to send with the API request
 * @param {object} [options={}] Object with additional options passed to the gateway. Please see
 * the gateway documentation for more information
 * @param {object} [actionMeta={}] Additional properties to set on the 'meta' property of the action
 * so we can identify the request in our reducers
 */
export const apiRequest = (
  method,
  actionType,
  gatewayType,
  path,
  data = null,
  options = {},
  actionMeta = {},
) => (dispatch, getState) => {
  const gatewayInstance = getValue(gatewayType);
  if (
    WP_DEFINE_DEVELOPMENT &&
    gatewayInstance.authEnabled &&
    WP_DEFINE_IS_NODE &&
    WP_DEFINE_FORCE_FAIL_ON_SERVER_AUTH_GATEWAY
  ) {
    const preparedState = getState().init.prepared;
    const pendingInitActions = Object.keys(preparedState)
      .filter(key => preparedState[key] === false)
      .map(key => {
        // make key more readable:  Connect(Connect(name))[2] => name[2]
        const parsed = key.match(/^(?:[A-Za-z]+\()+([^)]+)[)]+(\[.*])?$/);
        return parsed ? `${parsed[1]}${parsed[2] || ''}` : key;
      });
    return Promise.reject(
      new Error(
        [
          'Trying to do an authenticated api call on the server with forceFailOnServerAuthGateway enabled:',
          actionType,
          `${method} ${gatewayType} ${path}`,
          'This is likely to come from one of these pending init actions:',
          ...pendingInitActions,
        ].join('\n'),
      ),
    );
  }

  return dispatch(
    createAction(
      actionType,
      null,
      (_, meta) => meta,
    )(
      gatewayInstance[method](path, data, {
        ...options,
        getState,
      }),
      { api: { data, options, path }, ...actionMeta },
    ),
  );
};

/**
 * Wrapper action for 'apiRequest()' that sets the method to 'get'. All other
 * parameters are the same.
 * @function apiGet
 */
export const apiGet = (...requestArgs) => apiRequest('get', ...requestArgs);

/**
 * Wrapper action for 'apiRequest()' that sets the method to 'post'. All other
 * parameters are the same.
 * @function apiPost
 */
export const apiPost = (...requestArgs) => apiRequest('post', ...requestArgs);

/**
 * Wrapper action for 'apiRequest()' that sets the method to 'put'. All other
 * parameters are the same.
 * @function apiPut
 */
export const apiPut = (...requestArgs) => apiRequest('put', ...requestArgs);

/**
 * Wrapper action for 'apiRequest()' that sets the method to 'patch'. All other
 * parameters are the same.
 * @function apiPatch
 */
export const apiPatch = (...requestArgs) => apiRequest('patch', ...requestArgs);

/**
 * Wrapper action for 'apiRequest()' that sets the method to 'delete'. All other
 * parameters are the same.
 * @function apiDelete
 */
export const apiDelete = (...requestArgs) => apiRequest('delete', ...requestArgs);

/**
 * Wrapper action for 'apiRequest()' that sets the method to 'head'. All other
 * parameters are the same.
 * The HEAD method asks for a response identical to that of a GET request,
 * but without the response body.
 * @function apiHead
 */
export const apiHead = (...requestArgs) => apiRequest('head', ...requestArgs);