All files / src/containers/ApiCalls ApiAction.js

92.31% Statements 36/39
96.15% Branches 25/26
71.43% Functions 5/7
92.31% Lines 36/39
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100      6x 6x 6x 6x       6x 6x       34x 34x       34x 4x     30x   30x 1x     29x 1x     28x   28x 1x       27x 1x       26x 1x       25x 2x     23x 2x     23x         23x 15x     23x       33x 1x     32x       6x       5x       52x                      
import is from 'is_js';
import log from 'domain/log';
 
const TYPE_REQUEST = /_REQUEST$/i;
const TYPE_SUCCESS = /_SUCCESS$/i;
const TYPE_FAILURE = /_FAILURE$/i;
const TYPE_ANY = /(_REQUEST|_SUCCESS|_FAILURE)$/i;
 
class InvalidAction extends Error { }
 
const FINGERPRINT = Symbol('ApiAction');
const TIMESTAMP = Symbol('ApiAction/Timestamp');
 
export default class ApiAction {
  static create(originalAction) {
    const action = Object.assign({}, originalAction);
    Iif (is.not.object(action)) {
      throw new InvalidAction('An action should be an object');
    }
 
    if (is.not.string(action.url)) {
      throw new InvalidAction('The action should have a url property of type string');
    }
 
    action.url = action.url.toLowerCase();
 
    if (is.not.string(action.method)) {
      throw new InvalidAction('The action should have a method property of type string');
    }
 
    if (! /GET|PUT|DELETE|POST/i.test(action.method)) {
      throw new InvalidAction('The action should have a method property of type string');
    }
 
    action.method = action.method.toUpperCase();
 
    if (is.not.string(action.type)) {
      throw new InvalidAction('The action should have a type property of type string. ' +
          `Got one with a type of ${typeof action.type}`);
    }
 
    if (! TYPE_ANY.test(action.type)) {
      throw new InvalidAction('The type property of an action should end ' +
          `with _REQUEST, _SUCCESS or _FAILURE. Got ${action.type}`);
    }
 
    if (/[a-z]/.test(action.type)) {
      throw new InvalidAction('The type property of an action ' +
          `should not contain lower case letter. Got ${action.type}`);
    }
 
    if (ApiAction.isFailure(action) && is.not.existy(action.error)) {
      throw new InvalidAction('action.error should be defined for failed calls');
    }
 
    if (is.existy(action.error) && ! (action.error instanceof Error)) {
      action.error = new Error(action.error);
    }
 
    const newAction = Object.assign(action, {
      [FINGERPRINT]: true,
      [TIMESTAMP]: new Date(),
    });
 
    if (ApiAction.isFailure(newAction)) {
      log.error(newAction.error);
    }
 
    return Object.freeze(newAction);
  }
 
  static isApiAction(object) {
    if (is.not.object(object)) {
      return false;
    }
 
    return !! object[FINGERPRINT];
  }
 
  static isStarted(action) {
    return TYPE_REQUEST.test(action.type);
  }
 
  static isSuccess(action) {
    return TYPE_SUCCESS.test(action.type);
  }
 
  static isFailure(action) {
    return TYPE_FAILURE.test(action.type);
  }
 
  static getApiType(action) {
    return action.type.replace(TYPE_ANY, '');
  }
 
  static getTimestamp(action) {
    return action[TIMESTAMP];
  }
}