Skip to content

Instantly share code, notes, and snippets.

@arindampradhan
Last active July 15, 2018 14:47
Show Gist options
  • Save arindampradhan/56a83db44ddd84ad234a5baa1984cfdf to your computer and use it in GitHub Desktop.
Save arindampradhan/56a83db44ddd84ad234a5baa1984cfdf to your computer and use it in GitHub Desktop.
Axios service wrapper to wrap around a redux store. [SIMILAR TO REDUX-FORM]

request.js

/* eslint-disable */
/**
 * Axios Request Wrapper
 * ---------------------
 *  wraps arouund axios and redux
 */
/////////////////////
// USAGE
/////////////////////
// import request from 'utils/request';
//
// Simple Usage
// --------------------
// request({
//   action: 'OFFER',
//   method: 'get',
//   url: '/path/offer'
// }).then((resp) => {
//   console.log(resp);
// })
//

import axios from 'axios';
import { store } from 'app.js';
import tracker from './requestTracker';

/**
 * Redux
 */
export const SUCCESS_SUFFIX = '_SUCCESS';
export const FAILURE_SUFFIX = '_FAILURE';
export const REQUEST_SUFFIX = '_REQUEST';
export const DEFAULTACTION_NAME = 'API';

// use it in redcer
export function getActionType(action) {
  if (!action) return {};
  return {
    REQUEST: `${action}${REQUEST_SUFFIX}`.toUpperCase(),
    SUCCESS: `${action}${SUCCESS_SUFFIX}`.toUpperCase(),
    FAILURE: `${action}${FAILURE_SUFFIX}`.toUpperCase(),
  };
}

function withStore(type, payload) {
  return type ? store.dispatch({ type, payload }) : null;
}

/**
 * Request Wrapper with default success/error actions
 */

export const client = axios.create({
  baseURL: null,
});

const request = function(options) {
  // Redux helper
  const { action } = options;
  let actions = getActionType(action);
  tracker.set(action);
  withStore(actions.REQUEST, true);

  const onSuccess = function(response) {
    withStore(actions.SUCCESS, response.data);
    console.debug('Request Successful!', response);
    return {
      header: { status: response.status, statusText: response.statusText },
      ...response.data,
    };
  };

  const onError = function(error) {
    withStore(actions.FAILURE, { error: true, message: error.message });
    console.error('Request Failed:', error.config);

    if (error.response) {
      // Request was made but server responded with something
      // other than 2xx
      console.error('Status:', error.response.status);
      console.error('Data:', error.response.data);
      console.error('Headers:', error.response.headers);
    } else {
      // Something else happened while setting up the request
      // triggered the error
      console.error('Error Message:', error.message);
    }

    return Promise.reject(error.response || error.message);
  };

  return client(options)
    .then(onSuccess)
    .catch(onError);
};

window.request = request; // for development mode
export default request;

requestTracker.js

import { getActionType } from './request';

export class RequestTracker {
  reducers = new Set([]);
  actions = new Set([]);

  set = actionName => {
    if (!actionName) return;
    if (this.reducers.has(actionName)) return;
    if (typeof actionName !== 'string') {
      throw new Error('actionName must be string!');
    }

    this.reducers.add(actionName);
    const actns = getActionType(actionName);

    // structure
    const o = {
      actionName,
      actions: actns,
    };
    this.actions.add(o);
  };

  get = actionName => {
    const exists = this.reducers.filter(item => item === actionName).length;
    const ans = this.actions.filter(item => item.actionName === actionName);

    if (!exists) return undefined;
    if (ans.length > 0) {
      return ans[0].actions;
    }
    return undefined;
  };
}

const tracker = new RequestTracker();
export default tracker;

requestReducer.js

/**
 * A reducer that keeps track of ./request calls
 */
import tracker from './requestTracker';

const intialState = {};
export const requestReducer = (state = intialState, action) => {
  const { type, payload } = action;
  let newState = { ...state };
  if (!tracker) return newState;

  tracker.actions.forEach(actionGroup => {
    const { actions, actionName } = actionGroup;

    switch (type) {
      case actions.REQUEST:
        newState[actionName] = { request: payload };
        break;
      case actions.SUCCESS:
        newState[actionName] = { data: payload, request: false };
        break;
      case actions.FAILURE:
        newState[actionName] = { error: payload, request: false };
        break;
      default:
        newState = { ...state };
    }
  });

  return newState;
};
export default requestReducer;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment