Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 19 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ RSAAs are identified by the presence of an `[RSAA]` property, where [`RSAA`](#rs
- [Exports](#exports)
- [`RSAA`](#rsaa)
- [`apiMiddleware`](#apimiddleware)
- [`createMiddleware(options)`](#createmiddlewareoptions)
- [`isRSAA(action)`](#isrsaaaction)
- [`validateRSAA(action)`](#validatersaaaction)
- [`isValidRSAA(action)`](#isvalidrsaaaction)
Expand All @@ -64,6 +65,7 @@ RSAAs are identified by the presence of an `[RSAA]` property, where [`RSAA`](#rs
- [`[RSAA].credentials`](#rsaacredentials-1)
- [`[RSAA].bailout`](#rsaabailout)
- [`[RSAA].fetch`](#rsaafetch-1)
- [`[RSAA].ok`](#rsaaok)
- [`[RSAA].types`](#rsaatypes)
- [Type descriptors](#type-descriptors)
- [History](#history)
Expand Down Expand Up @@ -690,6 +692,15 @@ A JavaScript `String` whose presence as a key in an action signals that `redux-a

The Redux middleware itself.

#### `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)`

A function that returns `true` if `action` has an `[RSAA]` property, and `false` otherwise.
Expand Down Expand Up @@ -822,11 +833,12 @@ The `[RSAA]` property MAY
- have an `options` property,
- have a `credentials` property,
- 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`.

#### `[RSAA].endpoint`

Expand Down Expand Up @@ -860,7 +872,11 @@ The optional `[RSAA].bailout` property MUST be a boolean or a function.

#### `[RSAA].fetch`

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`

Expand Down
4 changes: 3 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
* @exports {error} RequestError
* @exports {error} ApiError
* @exports {function} getJSON
* @exports {function} createMiddleware
* @exports {ReduxMiddleWare} apiMiddleware
*/

Expand All @@ -32,7 +33,7 @@ import RSAA from './RSAA';
import { isRSAA, validateRSAA, isValidRSAA } from './validation';
import { InvalidRSAA, InternalError, RequestError, ApiError } from './errors';
import { getJSON } from './util';
import { apiMiddleware } from './middleware';
import { apiMiddleware, createMiddleware } from './middleware';

export {
RSAA,
Expand All @@ -44,5 +45,6 @@ export {
RequestError,
ApiError,
getJSON,
createMiddleware,
apiMiddleware
};
60 changes: 51 additions & 9 deletions src/middleware.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,30 @@
import RSAA from './RSAA';
import { isRSAA, validateRSAA } from './validation';
import { InvalidRSAA, RequestError } from './errors';
import { InvalidRSAA, RequestError, InternalError } from './errors';
import { normalizeTypeDescriptors, actionWith } from './util';

/**
* A Redux middleware that processes RSAA actions.
* Default options for redux-api-middleware
* These can be customized by passing options into `createMiddleware`
* @type {Object}
*/
const defaults = {
ok: res => res.ok,
fetch
};

/**
* A middleware creator used to create a ReduxApiMiddleware
* with custom defaults
*
* @type {ReduxMiddleware}
* @type {function}
* @returns {ReduxMiddleware}
* @access public
*/
function apiMiddleware({ getState }) {
return next => action => {
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);
Expand Down Expand Up @@ -42,7 +56,8 @@ function apiMiddleware({ getState }) {
body,
headers,
options = {},
fetch: doFetch = fetch
fetch: doFetch = middlewareOptions.fetch,
ok = middlewareOptions.ok
} = callAPI;
const { method, credentials, bailout, types } = callAPI;
const [requestType, successType, failureType] = normalizeTypeDescriptors(
Expand Down Expand Up @@ -152,9 +167,10 @@ function apiMiddleware({ getState }) {
next(requestType);
}

let res;
try {
// Make the API call
var res = await doFetch(endpoint, {
res = await doFetch(endpoint, {
...options,
method,
body: body || undefined,
Expand All @@ -175,8 +191,24 @@ function apiMiddleware({ getState }) {
);
}

let isOk;
try {
isOk = ok(res);
} catch (e) {
return next(
await actionWith(
{
...failureType,
payload: new InternalError('[RSAA].ok function failed'),
error: true
},
[action, getState(), res]
)
);
}

// Process the server response
if (res.ok) {
if (isOk) {
return next(await actionWith(successType, [action, getState(), res]));
} else {
return next(
Expand All @@ -193,4 +225,14 @@ function apiMiddleware({ getState }) {
};
}

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

export { createMiddleware, apiMiddleware };
12 changes: 10 additions & 2 deletions src/validation.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ function validateRSAA(action) {
'credentials',
'bailout',
'types',
'fetch'
'fetch',
'ok'
];
const validMethods = [
'GET',
Expand Down Expand Up @@ -105,7 +106,8 @@ function validateRSAA(action) {
credentials,
types,
bailout,
fetch
fetch,
ok
} = callAPI;
if (typeof endpoint === 'undefined') {
validationErrors.push('[RSAA] must have an endpoint property');
Expand Down Expand Up @@ -194,6 +196,12 @@ function validateRSAA(action) {
}
}

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

return validationErrors;
}

Expand Down
Loading