Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

redux-api-middleware

Package Overview
Dependencies
Maintainers
2
Versions
42
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

redux-api-middleware - npm Package Compare versions

Comparing version 2.3.0 to 3.0.0-beta.0

6

lib/index.js

@@ -6,3 +6,3 @@ 'use strict';

});
exports.apiMiddleware = exports.getJSON = exports.ApiError = exports.RequestError = exports.InternalError = exports.InvalidRSAA = exports.isValidRSAA = exports.validateRSAA = exports.isRSAA = exports.RSAA = exports.CALL_API = undefined;
exports.apiMiddleware = exports.createMiddleware = exports.getJSON = exports.ApiError = exports.RequestError = exports.InternalError = exports.InvalidRSAA = exports.isValidRSAA = exports.validateRSAA = exports.isRSAA = exports.RSAA = undefined;

@@ -23,3 +23,2 @@ var _RSAA = require('./RSAA');

exports.CALL_API = _RSAA2.default;
exports.RSAA = _RSAA2.default;

@@ -34,2 +33,3 @@ exports.isRSAA = _validation.isRSAA;

exports.getJSON = _util.getJSON;
exports.createMiddleware = _middleware.createMiddleware;
exports.apiMiddleware = _middleware.apiMiddleware; /**

@@ -40,3 +40,2 @@ * Redux middleware for calling an API

* @exports {string} RSAA
* @exports {string} CALL_API - alias of RSAA, to be deprecated in v3
* @exports {function} isRSAA

@@ -50,2 +49,3 @@ * @exports {function} validateRSAA

* @exports {function} getJSON
* @exports {function} createMiddleware
* @exports {ReduxMiddleWare} apiMiddleware

@@ -52,0 +52,0 @@ */

@@ -6,3 +6,3 @@ 'use strict';

});
exports.apiMiddleware = undefined;
exports.apiMiddleware = exports.createMiddleware = undefined;

@@ -25,2 +25,6 @@ var _regenerator = require('babel-runtime/regenerator');

var _assign = require('babel-runtime/core-js/object/assign');
var _assign2 = _interopRequireDefault(_assign);
var _RSAA = require('./RSAA');

@@ -39,271 +43,313 @@

/**
* A Redux middleware that processes RSAA actions.
* Default options for redux-api-middleware
* These can be customized by passing options into `createMiddleware`
* @type {Object}
*/
var defaults = {
ok: function ok(res) {
return res.ok;
},
fetch: fetch
};
/**
* A middleware creator used to create a ReduxApiMiddleware
* with custom defaults
*
* @type {ReduxMiddleware}
* @type {function}
* @returns {ReduxMiddleware}
* @access public
*/
function apiMiddleware(_ref) {
function createMiddleware() {
var _this = this;
var getState = _ref.getState;
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
return function (next) {
return function (action) {
// Do not process actions without an [RSAA] property
if (!(0, _validation.isRSAA)(action)) {
return next(action);
}
var middlewareOptions = (0, _assign2.default)({}, defaults, options);
return (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee() {
var validationErrors, _callAPI, _requestType, callAPI, endpoint, body, headers, _callAPI$options, options, _callAPI$fetch, doFetch, method, credentials, bailout, types, _normalizeTypeDescrip, _normalizeTypeDescrip2, requestType, successType, failureType, res;
return function (_ref) {
var getState = _ref.getState;
return function (next) {
return function (action) {
// Do not process actions without an [RSAA] property
if (!(0, _validation.isRSAA)(action)) {
return next(action);
}
return _regenerator2.default.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
// Try to dispatch an error request FSA for invalid RSAAs
validationErrors = (0, _validation.validateRSAA)(action);
return (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee() {
var validationErrors, _callAPI, _requestType, callAPI, endpoint, body, headers, _callAPI$options, options, _callAPI$fetch, doFetch, _callAPI$ok, ok, method, credentials, bailout, types, _normalizeTypeDescrip, _normalizeTypeDescrip2, requestType, successType, failureType, res, isOk;
if (!validationErrors.length) {
_context.next = 5;
break;
}
return _regenerator2.default.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
// Try to dispatch an error request FSA for invalid RSAAs
validationErrors = (0, _validation.validateRSAA)(action);
_callAPI = action[_RSAA2.default];
if (!validationErrors.length) {
_context.next = 5;
break;
}
if (_callAPI.types && Array.isArray(_callAPI.types)) {
_requestType = _callAPI.types[0];
_callAPI = action[_RSAA2.default];
if (_requestType && _requestType.type) {
_requestType = _requestType.type;
if (_callAPI.types && Array.isArray(_callAPI.types)) {
_requestType = _callAPI.types[0];
if (_requestType && _requestType.type) {
_requestType = _requestType.type;
}
next({
type: _requestType,
payload: new _errors.InvalidRSAA(validationErrors),
error: true
});
}
next({
type: _requestType,
payload: new _errors.InvalidRSAA(validationErrors),
error: true
});
}
return _context.abrupt('return');
return _context.abrupt('return');
case 5:
case 5:
// Parse the validated RSAA action
callAPI = action[_RSAA2.default];
endpoint = callAPI.endpoint, body = callAPI.body, headers = callAPI.headers, _callAPI$options = callAPI.options, options = _callAPI$options === undefined ? {} : _callAPI$options, _callAPI$fetch = callAPI.fetch, doFetch = _callAPI$fetch === undefined ? fetch : _callAPI$fetch;
method = callAPI.method, credentials = callAPI.credentials, bailout = callAPI.bailout, types = callAPI.types;
_normalizeTypeDescrip = (0, _util.normalizeTypeDescriptors)(types), _normalizeTypeDescrip2 = (0, _slicedToArray3.default)(_normalizeTypeDescrip, 3), requestType = _normalizeTypeDescrip2[0], successType = _normalizeTypeDescrip2[1], failureType = _normalizeTypeDescrip2[2];
// Parse the validated RSAA action
callAPI = action[_RSAA2.default];
endpoint = callAPI.endpoint, body = callAPI.body, headers = callAPI.headers, _callAPI$options = callAPI.options, options = _callAPI$options === undefined ? {} : _callAPI$options, _callAPI$fetch = callAPI.fetch, doFetch = _callAPI$fetch === undefined ? middlewareOptions.fetch : _callAPI$fetch, _callAPI$ok = callAPI.ok, ok = _callAPI$ok === undefined ? middlewareOptions.ok : _callAPI$ok;
method = callAPI.method, credentials = callAPI.credentials, bailout = callAPI.bailout, types = callAPI.types;
_normalizeTypeDescrip = (0, _util.normalizeTypeDescriptors)(types), _normalizeTypeDescrip2 = (0, _slicedToArray3.default)(_normalizeTypeDescrip, 3), requestType = _normalizeTypeDescrip2[0], successType = _normalizeTypeDescrip2[1], failureType = _normalizeTypeDescrip2[2];
// Should we bail out?
// Should we bail out?
_context.prev = 9;
_context.prev = 9;
if (!(typeof bailout === 'boolean' && bailout || typeof bailout === 'function' && bailout(getState()))) {
_context.next = 12;
if (!(typeof bailout === 'boolean' && bailout || typeof bailout === 'function' && bailout(getState()))) {
_context.next = 12;
break;
}
return _context.abrupt('return');
case 12:
_context.next = 21;
break;
}
return _context.abrupt('return');
case 14:
_context.prev = 14;
_context.t0 = _context['catch'](9);
_context.t1 = next;
_context.next = 19;
return (0, _util.actionWith)((0, _extends3.default)({}, requestType, {
payload: new _errors.RequestError('[RSAA].bailout function failed'),
error: true
}), [action, getState()]);
case 12:
_context.next = 21;
break;
case 19:
_context.t2 = _context.sent;
return _context.abrupt('return', (0, _context.t1)(_context.t2));
case 14:
_context.prev = 14;
_context.t0 = _context['catch'](9);
_context.t1 = next;
_context.next = 19;
return (0, _util.actionWith)((0, _extends3.default)({}, requestType, {
payload: new _errors.RequestError('[RSAA].bailout function failed'),
error: true
}), [action, getState()]);
case 21:
if (!(typeof endpoint === 'function')) {
_context.next = 33;
break;
}
case 19:
_context.t2 = _context.sent;
return _context.abrupt('return', (0, _context.t1)(_context.t2));
_context.prev = 22;
case 21:
if (!(typeof endpoint === 'function')) {
endpoint = endpoint(getState());
_context.next = 33;
break;
}
_context.prev = 22;
case 26:
_context.prev = 26;
_context.t3 = _context['catch'](22);
_context.t4 = next;
_context.next = 31;
return (0, _util.actionWith)((0, _extends3.default)({}, requestType, {
payload: new _errors.RequestError('[RSAA].endpoint function failed'),
error: true
}), [action, getState()]);
endpoint = endpoint(getState());
_context.next = 33;
break;
case 31:
_context.t5 = _context.sent;
return _context.abrupt('return', (0, _context.t4)(_context.t5));
case 26:
_context.prev = 26;
_context.t3 = _context['catch'](22);
_context.t4 = next;
_context.next = 31;
return (0, _util.actionWith)((0, _extends3.default)({}, requestType, {
payload: new _errors.RequestError('[RSAA].endpoint function failed'),
error: true
}), [action, getState()]);
case 33:
if (!(typeof body === 'function')) {
_context.next = 45;
break;
}
case 31:
_context.t5 = _context.sent;
return _context.abrupt('return', (0, _context.t4)(_context.t5));
_context.prev = 34;
case 33:
if (!(typeof body === 'function')) {
body = body(getState());
_context.next = 45;
break;
}
_context.prev = 34;
case 38:
_context.prev = 38;
_context.t6 = _context['catch'](34);
_context.t7 = next;
_context.next = 43;
return (0, _util.actionWith)((0, _extends3.default)({}, requestType, {
payload: new _errors.RequestError('[RSAA].body function failed'),
error: true
}), [action, getState()]);
body = body(getState());
_context.next = 45;
break;
case 43:
_context.t8 = _context.sent;
return _context.abrupt('return', (0, _context.t7)(_context.t8));
case 38:
_context.prev = 38;
_context.t6 = _context['catch'](34);
_context.t7 = next;
_context.next = 43;
return (0, _util.actionWith)((0, _extends3.default)({}, requestType, {
payload: new _errors.RequestError('[RSAA].body function failed'),
error: true
}), [action, getState()]);
case 45:
if (!(typeof headers === 'function')) {
_context.next = 57;
break;
}
case 43:
_context.t8 = _context.sent;
return _context.abrupt('return', (0, _context.t7)(_context.t8));
_context.prev = 46;
case 45:
if (!(typeof headers === 'function')) {
headers = headers(getState());
_context.next = 57;
break;
}
_context.prev = 46;
case 50:
_context.prev = 50;
_context.t9 = _context['catch'](46);
_context.t10 = next;
_context.next = 55;
return (0, _util.actionWith)((0, _extends3.default)({}, requestType, {
payload: new _errors.RequestError('[RSAA].headers function failed'),
error: true
}), [action, getState()]);
headers = headers(getState());
_context.next = 57;
break;
case 55:
_context.t11 = _context.sent;
return _context.abrupt('return', (0, _context.t10)(_context.t11));
case 50:
_context.prev = 50;
_context.t9 = _context['catch'](46);
_context.t10 = next;
_context.next = 55;
return (0, _util.actionWith)((0, _extends3.default)({}, requestType, {
payload: new _errors.RequestError('[RSAA].headers function failed'),
error: true
}), [action, getState()]);
case 57:
if (!(typeof options === 'function')) {
_context.next = 69;
break;
}
case 55:
_context.t11 = _context.sent;
return _context.abrupt('return', (0, _context.t10)(_context.t11));
_context.prev = 58;
case 57:
if (!(typeof options === 'function')) {
options = options(getState());
_context.next = 69;
break;
}
_context.prev = 58;
case 62:
_context.prev = 62;
_context.t12 = _context['catch'](58);
_context.t13 = next;
_context.next = 67;
return (0, _util.actionWith)((0, _extends3.default)({}, requestType, {
payload: new _errors.RequestError('[RSAA].options function failed'),
error: true
}), [action, getState()]);
options = options(getState());
_context.next = 69;
break;
case 67:
_context.t14 = _context.sent;
return _context.abrupt('return', (0, _context.t13)(_context.t14));
case 62:
_context.prev = 62;
_context.t12 = _context['catch'](58);
_context.t13 = next;
_context.next = 67;
return (0, _util.actionWith)((0, _extends3.default)({}, requestType, {
payload: new _errors.RequestError('[RSAA].options function failed'),
error: true
}), [action, getState()]);
case 69:
if (!(typeof requestType.payload === 'function' || typeof requestType.meta === 'function')) {
_context.next = 77;
break;
}
case 67:
_context.t14 = _context.sent;
return _context.abrupt('return', (0, _context.t13)(_context.t14));
_context.t15 = next;
_context.next = 73;
return (0, _util.actionWith)(requestType, [action, getState()]);
case 69:
if (!(typeof requestType.payload === 'function' || typeof requestType.meta === 'function')) {
_context.next = 77;
case 73:
_context.t16 = _context.sent;
(0, _context.t15)(_context.t16);
_context.next = 78;
break;
}
_context.t15 = next;
_context.next = 73;
return (0, _util.actionWith)(requestType, [action, getState()]);
case 77:
next(requestType);
case 73:
_context.t16 = _context.sent;
(0, _context.t15)(_context.t16);
_context.next = 78;
break;
case 78:
res = void 0;
_context.prev = 79;
_context.next = 82;
return doFetch(endpoint, (0, _extends3.default)({}, options, {
method: method,
body: body || undefined,
credentials: credentials,
headers: headers || {}
}));
case 77:
next(requestType);
case 82:
res = _context.sent;
_context.next = 92;
break;
case 78:
_context.prev = 78;
_context.next = 81;
return doFetch(endpoint, (0, _extends3.default)({}, options, {
method: method,
body: body || undefined,
credentials: credentials,
headers: headers || {}
}));
case 85:
_context.prev = 85;
_context.t17 = _context['catch'](79);
_context.t18 = next;
_context.next = 90;
return (0, _util.actionWith)((0, _extends3.default)({}, failureType, {
payload: new _errors.RequestError(_context.t17.message),
error: true
}), [action, getState()]);
case 81:
res = _context.sent;
_context.next = 91;
break;
case 90:
_context.t19 = _context.sent;
return _context.abrupt('return', (0, _context.t18)(_context.t19));
case 84:
_context.prev = 84;
_context.t17 = _context['catch'](78);
_context.t18 = next;
_context.next = 89;
return (0, _util.actionWith)((0, _extends3.default)({}, requestType, {
payload: new _errors.RequestError(_context.t17.message),
error: true
}), [action, getState()]);
case 92:
isOk = void 0;
_context.prev = 93;
case 89:
_context.t19 = _context.sent;
return _context.abrupt('return', (0, _context.t18)(_context.t19));
case 91:
if (!res.ok) {
_context.next = 99;
isOk = ok(res);
_context.next = 104;
break;
}
_context.t20 = next;
_context.next = 95;
return (0, _util.actionWith)(successType, [action, getState(), res]);
case 97:
_context.prev = 97;
_context.t20 = _context['catch'](93);
_context.t21 = next;
_context.next = 102;
return (0, _util.actionWith)((0, _extends3.default)({}, failureType, {
payload: new _errors.InternalError('[RSAA].ok function failed'),
error: true
}), [action, getState(), res]);
case 95:
_context.t21 = _context.sent;
return _context.abrupt('return', (0, _context.t20)(_context.t21));
case 102:
_context.t22 = _context.sent;
return _context.abrupt('return', (0, _context.t21)(_context.t22));
case 99:
_context.t22 = next;
_context.next = 102;
return (0, _util.actionWith)((0, _extends3.default)({}, failureType, {
error: true
}), [action, getState(), res]);
case 104:
if (!isOk) {
_context.next = 112;
break;
}
case 102:
_context.t23 = _context.sent;
return _context.abrupt('return', (0, _context.t22)(_context.t23));
_context.t23 = next;
_context.next = 108;
return (0, _util.actionWith)(successType, [action, getState(), res]);
case 104:
case 'end':
return _context.stop();
case 108:
_context.t24 = _context.sent;
return _context.abrupt('return', (0, _context.t23)(_context.t24));
case 112:
_context.t25 = next;
_context.next = 115;
return (0, _util.actionWith)((0, _extends3.default)({}, failureType, {
error: true
}), [action, getState(), res]);
case 115:
_context.t26 = _context.sent;
return _context.abrupt('return', (0, _context.t25)(_context.t26));
case 117:
case 'end':
return _context.stop();
}
}
}
}, _callee, _this, [[9, 14], [22, 26], [34, 38], [46, 50], [58, 62], [78, 84]]);
}))();
}, _callee, _this, [[9, 14], [22, 26], [34, 38], [46, 50], [58, 62], [79, 85], [93, 97]]);
}))();
};
};

@@ -313,2 +359,15 @@ };

/**
* A Redux middleware that processes RSAA actions.
*
* @type {ReduxMiddleware}
* @access public
*/
function apiMiddleware(_ref3) {
var getState = _ref3.getState;
return createMiddleware()({ getState: getState });
}
exports.createMiddleware = createMiddleware;
exports.apiMiddleware = apiMiddleware;

@@ -77,3 +77,3 @@ 'use strict';

var validationErrors = [];
var validCallAPIKeys = ['endpoint', 'options', 'method', 'body', 'headers', 'credentials', 'bailout', 'types', 'fetch'];
var validCallAPIKeys = ['endpoint', 'options', 'method', 'body', 'headers', 'credentials', 'bailout', 'types', 'fetch', 'ok'];
var validMethods = ['GET', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'];

@@ -87,8 +87,2 @@ var validCredentials = ['omit', 'same-origin', 'include'];

for (var key in action) {
if (key !== _RSAA2.default) {
validationErrors.push('Invalid root key: ' + key);
}
}
var callAPI = action[_RSAA2.default];

@@ -98,5 +92,5 @@ if (!(0, _lodash2.default)(callAPI)) {

}
for (var _key in callAPI) {
if (!~validCallAPIKeys.indexOf(_key)) {
validationErrors.push('Invalid [RSAA] key: ' + _key);
for (var key in callAPI) {
if (!~validCallAPIKeys.indexOf(key)) {
validationErrors.push('Invalid [RSAA] key: ' + key);
}

@@ -112,3 +106,4 @@ }

bailout = callAPI.bailout,
fetch = callAPI.fetch;
fetch = callAPI.fetch,
ok = callAPI.ok;

@@ -172,2 +167,8 @@ if (typeof endpoint === 'undefined') {

if (typeof ok !== 'undefined') {
if (typeof ok !== 'function') {
validationErrors.push('[RSAA].ok property must be a function');
}
}
return validationErrors;

@@ -174,0 +175,0 @@ }

{
"name": "redux-api-middleware",
"version": "2.3.0",
"version": "3.0.0-beta.0",
"description": "Redux middleware for calling an API.",

@@ -5,0 +5,0 @@ "main": "lib/index.js",

@@ -7,30 +7,77 @@ redux-api-middleware

This middleware receives [*Redux Standard API-calling Actions*](#redux-standard-api-calling-actions) (RSAAs) and dispatches [*Flux Standard Actions*](#flux-standard-actions) (FSAs) to the next middleware.
RSAAs are identified by the presence of an `[RSAA]` property, where [`RSAA`](#rsaa) is a `String` constant defined in, and exported by `redux-api-middleware`. They contain information describing an API call and three different types of FSAs, known as the *request*, *success* and *failure* FSAs.
## Table of contents
1. [Introduction](#introduction)
- [A simple example](#a-simple-example)
- [Breaking Changes in 2.0 Release](#breaking-changes-in-20-release)
2. [Installation](#installation)
3. [Usage](#usage)
- [Defining the API call](#defining-the-api-call)
- [Bailing out](#bailing-out)
- [Lifecycle](#lifecycle)
- [Customizing the dispatched FSAs](#customizing-the-dispatched-fsas)
4. [Reference](#reference)
- [Exports](#exports)
- [Flux Standard Actions](#flux-standard-actions)
- [Redux Standard API-calling Actions](#redux-standard-api-calling-actions)
5. [History](#history)
6. [Tests](#tests)
7. [Upgrading from v1.0.x](#upgrading-from-v10x)
8. [License](License)
9. [Acknowledgements](#acknowledgements)
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
## Introduction
This middleware receives [*Redux Standard API-calling Actions*](#redux-standard-api-calling-actions) (RSAAs) and dispatches [*Flux Standard Actions*](#flux-standard-actions) (FSAs) to the next middleware.
- [Introduction](#introduction)
- [Breaking Changes in 2.0 Release](#breaking-changes-in-20-release)
- [Breaking Changes in 3.0 Release](#breaking-changes-in-30-release)
- [Installation](#installation)
- [configureStore.js](#configurestorejs)
- [app.js](#appjs)
- [Usage](#usage)
- [Defining the API call](#defining-the-api-call)
- [`[RSAA].endpoint`](#rsaaendpoint)
- [`[RSAA].method`](#rsaamethod)
- [`[RSAA].body`](#rsaabody)
- [`[RSAA].headers`](#rsaaheaders)
- [`[RSAA].options`](#rsaaoptions)
- [`[RSAA].credentials`](#rsaacredentials)
- [`[RSAA].fetch`](#rsaafetch)
- [Bailing out](#bailing-out)
- [Lifecycle](#lifecycle)
- [Customizing the dispatched FSAs](#customizing-the-dispatched-fsas)
- [Dispatching Thunks](#dispatching-thunks)
- [Testing](#testing)
- [Reference](#reference)
- [*Request* type descriptors](#request-type-descriptors)
- [*Success* type descriptors](#success-type-descriptors)
- [*Failure* type descriptors](#failure-type-descriptors)
- [Exports](#exports)
- [`RSAA`](#rsaa)
- [`apiMiddleware`](#apimiddleware)
- [`createMiddleware(options)`](#createmiddlewareoptions)
- [`isRSAA(action)`](#isrsaaaction)
- [`validateRSAA(action)`](#validatersaaaction)
- [`isValidRSAA(action)`](#isvalidrsaaaction)
- [`InvalidRSAA`](#invalidrsaa)
- [`InternalError`](#internalerror)
- [`RequestError`](#requesterror)
- [`ApiError`](#apierror)
- [`getJSON(res)`](#getjsonres)
- [Flux Standard Actions](#flux-standard-actions)
- [`type`](#type)
- [`payload`](#payload)
- [`error`](#error)
- [`meta`](#meta)
- [Redux Standard API-calling Actions](#redux-standard-api-calling-actions)
- [`[RSAA]`](#rsaa)
- [`[RSAA].endpoint`](#rsaaendpoint-1)
- [`[RSAA].method`](#rsaamethod-1)
- [`[RSAA].body`](#rsaabody-1)
- [`[RSAA].headers`](#rsaaheaders-1)
- [`[RSAA].options`](#rsaaoptions-1)
- [`[RSAA].credentials`](#rsaacredentials-1)
- [`[RSAA].bailout`](#rsaabailout)
- [`[RSAA].fetch`](#rsaafetch-1)
- [`[RSAA].ok`](#rsaaok)
- [`[RSAA].types`](#rsaatypes)
- [Type descriptors](#type-descriptors)
- [History](#history)
- [Tests](#tests)
- [Upgrading from v1.0.x](#upgrading-from-v10x)
- [Upgrading from v2.0.x](#upgrading-from-v20x)
- [License](#license)
- [Projects using redux-api-middleware](#projects-using-redux-api-middleware)
- [Acknowledgements](#acknowledgements)
RSAAs are identified by the presence of an `[RSAA]` property, where [`RSAA`](#rsaa) is a `String` constant defined in, and exported by `redux-api-middleware`. They contain information describing an API call and three different types of FSAs, known as the *request*, *success* and *failure* FSAs.
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
### A simple example
## Introduction

@@ -93,2 +140,6 @@ The following is a minimal RSAA action:

### Breaking Changes in 3.0 Release
See the [3.0 Release Notes](https://github.com/agraboso/redux-api-middleware/releases/tag/v3.0.0), and [Upgrading from v2.0.x](#upgrading-from-v20x) for details on upgrading.
## Installation

@@ -206,4 +257,7 @@

Example of modifying a request payload and status:
**Examples:**
<details>
<summary>Modify a response payload and status</summary>
```js

@@ -237,4 +291,6 @@ {

```
</details>
Example of skipping the request in favor of a cached response:
<details>
<summary>Modify a response status based on response json</summary>

@@ -246,2 +302,23 @@ ```js

fetch: async (...args) => {
const res = await fetch(...args);
const returnRes = res.clone(); // faster then above example with JSON.stringify
const json = await res.json(); // we need json just to check status
returnRes.status = json.error ? 500 : 200,
return returnRes;
}
...
}
}
```
</details>
<details>
<summary>Skip the request in favor of a cached response</summary>
```js
{
[RSAA]: {
...
fetch: async (...args) => {
const cached = await getCache('someKey');

@@ -268,2 +345,3 @@

```
</details>

@@ -299,4 +377,4 @@ ### Bailing out

If such an error occurs, a different *request* FSA will be dispatched (*instead* of the one described above). It will contain the following properties:
- `type`: the string constant in the first position of the `[RSAA].types` array;
If such an error occurs, a *failure* FSA will be dispatched containing the following properties:
- `type`: the string constant in the last position of the `[RSAA].types` array;
- `payload`: a [`RequestError`](#requesterror) object containing an error message;

@@ -326,4 +404,118 @@ - `error: true`.

#### *Request* type descriptors
### Dispatching Thunks
You can use `redux-thunk` to compose effects, dispatch custom actions on success/error, and implement other types of complex behavior.
See [the Redux docs on composition](https://github.com/reduxjs/redux-thunk#composition) for more in-depth information, or expand the example below.
<details>
<summary>Example</summary>
```js
export function patchAsyncExampleThunkChainedActionCreator(values) {
return async(dispatch, getState) => {
const actionResponse = await dispatch({
[RSAA]: {
endpoint: "...",
method: "PATCH",
body: JSON.stringify(values),
headers: {
"Accept": "application/json",
"Content-Type": "application/json",
},
types: [PATCH, PATCH_SUCCESS, PATCH_FAILED]
}
});
if (actionResponse.error) {
// the last dispatched action has errored, break out of the promise chain.
throw new Error("Promise flow received action error", actionResponse);
}
// you can EITHER return the above resolved promise (actionResponse) here...
return actionResponse;
// OR resolve another asyncAction here directly and pass the previous received payload value as argument...
return await yourOtherAsyncAction(actionResponse.payload.foo);
};
}
```
</details>
### Testing
To test `redux-api-middleware` calls inside our application, we can create a fetch mock in order to simulate the response of the call. The `fetch-mock` and `redux-mock-store`packages can be used for this purpose as shown in the following example:
**actions/user.js**
```javascript
export const USER_REQUEST = '@@user/USER_REQUEST'
export const USER_SUCCESS = '@@user/USER_SUCCESS'
export const USER_FAILURE = '@@user/USER_FAILURE'
export const getUser = () => ({
[RSAA]: {
endpoint: 'https://hostname/api/users/',
method: 'GET',
headers: { 'Content-Type': 'application/json' },
types: [
USER_REQUEST,
USER_SUCCESS,
USER_FAILURE
]
}
})
```
**actions/user.test.js**
```javascript
// This is a Jest test, fyi
import configureMockStore from 'redux-mock-store'
import { apiMiddleware } from 'redux-api-middleware'
import thunk from 'redux-thunk'
import fetchMock from 'fetch-mock'
import {getUser} from './user'
const middlewares = [ thunk, apiMiddleware ]
const mockStore = configureMockStore(middlewares)
describe('async user actions', () => {
// If we have several tests in our test suit, we might want to
// reset and restore the mocks after each test to avoid unexpected behaviors
afterEach(() => {
fetchMock.reset()
fetchMock.restore()
})
it('should dispatch USER_SUCCESS when getUser is called', () => {
// We create a mock store for our test data.
const store = mockStore({})
const body = {
email: 'EMAIL',
username: 'USERNAME'
}
// We build the mock for the fetch request.
// beware that the url must match the action endpoint.
fetchMock.getOnce(`https://hostname/api/users/`, {body: body, headers: {'content-type': 'application/json'}})
// We are going to verify the response with the following actions
const expectedActions = [
{type: actions.USER_REQUEST},
{type: actions.USER_SUCCESS, payload: body}
]
return store.dispatch(actions.getUser()).then(() => {
// Verify that all the actions in the store are the expected ones
expect(store.getActions()).toEqual(expectedActions)
})
})
})
```
## Reference
### *Request* type descriptors
`payload` and `meta` functions will be passed the RSAA action itself and the state of your Redux store.

@@ -389,3 +581,3 @@

#### *Success* type descriptors
### *Success* type descriptors

@@ -455,3 +647,3 @@ `payload` and `meta` functions will be passed the RSAA action itself, the state of your Redux store, and the raw server response.

#### *Failure* type descriptors
### *Failure* type descriptors

@@ -489,2 +681,3 @@ `payload` and `meta` functions will be passed the RSAA action itself, the state of your Redux store, and the raw server response &mdash; exactly as for *success* type descriptors. The `error` property of dispatched *failure* FSAs will always be set to `true`.

```
By default, *failure* FSAs will not contain a `meta` property, while their `payload` property will be evaluated from

@@ -498,4 +691,5 @@ ```js

## Reference
Note that *failure* FSAs dispatched due to fetch errors will not have a `res` argument into `meta` or `payload`. The `res` parameter will exist for completed requests that have resulted in errors, but not for failed requests.
### Exports

@@ -513,2 +707,11 @@

#### `createMiddleware(options)`
A function that creates an `apiMiddleware` with custom options.
The following `options` properties are used:
- `fetch` - provide a `fetch` API compatible function here to use instead of the default `window.fetch`
- `ok` - provide a function here to use as a status check in the RSAA flow instead of `(res) => res.ok`
#### `isRSAA(action)`

@@ -626,5 +829,5 @@

A *Redux Standard API-calling Action* MUST NOT
A *Redux Standard API-calling Action* MAY
- include properties other than `[RSAA]`.
- include properties other than `[RSAA]` (but will be ignored by redux-api-middleware).

@@ -647,7 +850,8 @@ #### `[RSAA]`

- have a `bailout` property,
- have a `fetch` property.
- have a `fetch` property,
- have an `ok` property.
The `[RSAA]` property MUST NOT
- include properties other than `endpoint`, `method`, `types`, `body`, `headers`, `options`, `credentials`, `bailout` and `fetch`.
- include properties other than `endpoint`, `method`, `types`, `body`, `headers`, `options`, `credentials`, `bailout`, `fetch` and `ok`.

@@ -686,4 +890,8 @@ #### `[RSAA].endpoint`

The optional `[RSAA].fetch` property MUST be a function.
The optional `[RSAA].fetch` property MUST be a function that conforms to the [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API).
#### `[RSAA].ok`
The optional `[RSAA].ok` property MUST be a function that accepts a response object and returns a boolean indicating if the request is a success or failure
#### `[RSAA].types`

@@ -724,4 +932,11 @@

- A new `options` config is added to pass your `fetch` implementation extra options other than `method`, `headers`, `body` and `credentials`
- `apiMiddleware` no longer returns a promise on actions without [RSAA]
- `apiMiddleware` no longer returns a promise on actions without [RSAA]
## Upgrading from v2.0.x
- The `CALL_API` alias has been removed
- Error handling around failed fetches has been updated (#175)
- Previously, a failed `fetch` would dispatch a `REQUEST` FSA followed by another `REQUEST` FSA with an error flag
- Now, a failed `fetch` will dispatch a `REQUEST` FSA followed by a `FAILURE` FSA
## License

@@ -728,0 +943,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc