All files / lib fetch.js

87.14% Statements 61/70
70.27% Branches 26/37
82.35% Functions 14/17
90.91% Lines 10/11
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 101 102 1036x                                                                                                                                                           6x   2x                   42x       2x   2x 2x 1x 1x 1x    
import fetch from 'isomorphic-fetch'
import isObject from 'lodash.isobject'
import {createAction} from 'redux-actions'
 
export const INCREMENT_FETCH = 'increment outstanding fetches'
export const DECREMENT_FETCH = 'decrement outstanding fetches'
export const FETCH = 'fetch'
export const FETCH_ERROR = 'fetch error'
 
export const incrementFetches = createAction(INCREMENT_FETCH)
export const decrementFetches = createAction(DECREMENT_FETCH)
export const fetchError = createAction(FETCH_ERROR)
export const fetchAction = createAction(FETCH)
 
export function middleware (store) {
  return (next) => (action) =>
    action.type === FETCH
      ? store.dispatch(incrementFetches()) && store.dispatch(runFetch(action.payload, store.getState()))
      : next(action)
}
 
export default fetchAction
 
/**
 * Calls fetch, adds Auth and Content header if needed. Automatically parses content based on type.
 *
 * @returns Promise
 */
 
function runFetch ({
  next,
  options = {},
  url
}, state) {
  const isJSON = isObject(options.body)
  return fetch(url, {
    ...options,
    body: isJSON ? JSON.stringify(options.body) : options.body,
    headers: {
      ...createAuthorizationHeader(state),
      ...createContentHeader(isJSON),
      ...(options.headers || {})
    }
  })
    .then(checkStatus)
    .then(createResponse)
    .then((response) => [decrementFetches(), next(response)])
    .catch((error) =>
      createErrorResponse(error)
        .then((response) => [decrementFetches(), fetchError(response), next(response, true)]))
}
 
function createAuthorizationHeader (state) {
  return state.user && state.user.idToken
    ? {Authorization: `bearer ${state.user.idToken}`}
    : {}
}
 
function checkStatus (res) {
  if (res.status >= 200 && res.status < 300) {
    return res
  } else {
    throw res
  }
}
 
function createContentHeader (isJSON) {
  return isJSON
    ? {'Accept': 'application/json', 'Content-Type': 'application/json;charset=UTF-8'}
    : {}
}
 
function createErrorResponse (res) {
  return res.headers
    ? createResponse(res)
    : Promise.resolve(res)
}
 
async function createResponse (res) {
  try {
    const value = await deserialize(res)
    return {
      url: res.url,
      status: res.status,
      statusText: res.statusText,
      headers: res.headers,
      value
    }
  } catch (err) {
    return {
      value: err
    }
  }
}
E
function deserialize (res) {
  const header = [res.headers.get('Content-Type'), res.headers.get('Content')].filter(Boolean)
  if (header.indexOf('application/json') > -1) return res.json()
  Iif (header.indexOf('application/ld+json') > -1) return res.json()
  Iif (header.indexOf('application/octet-stream') > -1) return res.arrayBuffer()
  return res.text()
}