text: const API_ROOT = 'http://www.twse.com.tw/ch/trading/exchange/STOCK_DAY/STOCK_DAY_print.php?genpage=genpage/Report201510/201510_F3_1_8_6452.php&type=csv'
  
  function callApi(endpoint, schema) {
  
    // 判斷endpoint是否包含了API網址
    const fullUrl = (endpoint.indexOf(API_ROOT) === -1) ? API_ROOT + endpoint : endpoint;
  
    return fetch(fullUrl)
      .then(response =>
        response.json().then(json => ({ json, response }))
      ).then(({ json, response }) => {
        if (!response.ok) {
          return Promise.reject(json);
        }
  
        const camelizedJson = camelizeKeys(json);
        const nextPageUrl = getNextPageUrl(response) || undefined;
  
        return Object.assign({},
          normalize(camelizedJson, schema),
          { nextPageUrl }
        );
      });
  }
  
  export const CALL_API = Symbol('Call API');
  
  export default store => next => action => {
  
    const callAPI = action[CALL_API];
  
    if (typeof callAPI === 'undefined') {
      return next(action);
    }
  
    let { endpoint } = callAPI;
    const { schema, types } = callAPI;
  
    if (typeof endpoint === 'function') {
      endpoint = endpoint(store.getState());
    }
  
    if (typeof endpoint !== 'string') {
      throw new Error('Specify a string endpoint URL.');
    }
    if (!schema) {
      throw new Error('Specify one of the exported Schemas.');
    }
    if (!Array.isArray(types) || types.length !== 3) {
      throw new Error('Expected an array of three action types.');
    }
    if (!types.every(type => typeof type === 'string')) {
      throw new Error('Expected action types to be strings.');
    }
  
    function actionWith(data) {
      const finalAction = Object.assign({}, action, data);
      delete finalAction[CALL_API];
      return finalAction;
    }
  
    const [requestType, successType, failureType] = types;
    next(actionWith({ type: requestType }));
  
    return callApi(endpoint, schema).then(
      response => next(actionWith({
        response,
        type: successType
      })),
      error => next(actionWith({
        type: failureType,
        error: error.message || 'Something bad happened'
      }))
    );
  };
  