Skip to content

Commit

Permalink
Merge pull request #194 from agraboso/custom-error-evaluation-docs-tests
Browse files Browse the repository at this point in the history
Add custom `ok` hander (#171) + cleanup, docs, and tests
  • Loading branch information
nason authored Jun 10, 2018
2 parents a0460d2 + 8d02399 commit 3a19b1b
Show file tree
Hide file tree
Showing 5 changed files with 337 additions and 125 deletions.
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

0 comments on commit 3a19b1b

Please sign in to comment.