UNPKG

redux-api-middleware

Version:
204 lines (171 loc) 6.61 kB
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } import RSAA from './RSAA'; import { isRSAA, validateRSAA } from './validation'; import { InvalidRSAA, RequestError, InternalError } from './errors'; import { normalizeTypeDescriptors, actionWith } from './util'; /** * Default options for redux-api-middleware * These can be customized by passing options into `createMiddleware` * @type {Object} */ const defaults = { ok: res => res.ok }; /** * A middleware creator used to create a ReduxApiMiddleware * with custom defaults * * @type {function} * @returns {ReduxMiddleware} * @access public */ function createMiddleware(options = {}) { const middlewareOptions = Object.assign({}, defaults, options); return ({ getState }) => next => action => { // Do not process actions without an [RSAA] property if (!isRSAA(action)) { return next(action); } return (async () => { // Try to dispatch an error request FSA for invalid RSAAs const validationErrors = validateRSAA(action); if (validationErrors.length) { const callAPI = action[RSAA]; if (callAPI.types && Array.isArray(callAPI.types)) { let requestType = callAPI.types[0]; if (requestType && requestType.type) { requestType = requestType.type; } next({ type: requestType, payload: new InvalidRSAA(validationErrors), error: true }); } return; } // Parse the validated RSAA action const callAPI = action[RSAA]; var { endpoint, body, headers, options = {}, fetch: doFetch = middlewareOptions.fetch || fetch, ok = middlewareOptions.ok } = callAPI; const { method, credentials, bailout, types } = callAPI; const [requestType, successType, failureType] = normalizeTypeDescriptors(types); // Should we bail out? try { if (typeof bailout === 'boolean' && bailout || typeof bailout === 'function' && bailout(getState())) { return; } } catch (e) { return next((await actionWith(_objectSpread({}, failureType, { payload: new RequestError('[RSAA].bailout function failed'), error: true }), [action, getState()]))); } // Process [RSAA].endpoint function if (typeof endpoint === 'function') { try { endpoint = await endpoint(getState()); } catch (e) { return next((await actionWith(_objectSpread({}, failureType, { payload: new RequestError('[RSAA].endpoint function failed'), error: true }), [action, getState()]))); } } // Process [RSAA].body function if (typeof body === 'function') { try { body = await body(getState()); } catch (e) { return next((await actionWith(_objectSpread({}, failureType, { payload: new RequestError('[RSAA].body function failed'), error: true }), [action, getState()]))); } } // Process [RSAA].headers function if (typeof headers === 'function') { try { headers = await headers(getState()); } catch (e) { return next((await actionWith(_objectSpread({}, failureType, { payload: new RequestError('[RSAA].headers function failed'), error: true }), [action, getState()]))); } } // Process [RSAA].options function if (typeof options === 'function') { try { options = await options(getState()); } catch (e) { return next((await actionWith(_objectSpread({}, failureType, { payload: new RequestError('[RSAA].options function failed'), error: true }), [action, getState()]))); } } // We can now dispatch the request FSA if (typeof requestType.payload === 'function' || typeof requestType.meta === 'function') { next((await actionWith(requestType, [action, getState()]))); } else { next(requestType); } let res; try { // Make the API call res = await doFetch(endpoint, _objectSpread({}, options, { method, body: body || undefined, credentials, headers: headers || {} })); } catch (e) { // The request was malformed, or there was a network error return next((await actionWith(_objectSpread({}, failureType, { payload: new RequestError(e.message), error: true }), [action, getState()]))); } let isOk; try { isOk = ok(res); } catch (e) { return next((await actionWith(_objectSpread({}, failureType, { payload: new InternalError('[RSAA].ok function failed'), error: true }), [action, getState(), res]))); } // Process the server response if (isOk) { return next((await actionWith(successType, [action, getState(), res]))); } else { return next((await actionWith(_objectSpread({}, failureType, { error: true }), [action, getState(), res]))); } })(); }; } /** * A Redux middleware that processes RSAA actions. * * @type {ReduxMiddleware} * @access public * @deprecated since v3.2.0 use `createMiddleware` */ function apiMiddleware({ getState }) { return createMiddleware()({ getState }); } export { createMiddleware, apiMiddleware };