Skip to content

Commit 266488c

Browse files
authored
Merge pull request #168 from agraboso/rsaa-body-as-function
Allow [RSAA].body to be passed as a function
2 parents 2e6d408 + 9b2dee5 commit 266488c

File tree

3 files changed

+90
-4
lines changed

3 files changed

+90
-4
lines changed

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,8 @@ The body of the API call.
146146

147147
`redux-api-middleware` uses the [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) to make the API call. `[RSAA].body` should hence be a valid body according to the [fetch specification](https://fetch.spec.whatwg.org). In most cases, this will be a JSON-encoded string or a [`FormData`](https://developer.mozilla.org/en/docs/Web/API/FormData) object.
148148

149+
It may also be a function taking the state of your Redux store as its argument, and returning a body as described above.
150+
149151
#### `[RSAA].headers`
150152

151153
The HTTP headers for the API call.
@@ -218,7 +220,7 @@ The `[RSAA].types` property controls the output of `redux-api-middleware`. The s
218220
- `type`: the string constant in the first position of the `[RSAA].types` array.
219221

220222
But errors may pop up at this stage, for several reasons:
221-
- `redux-api-middleware` has to call those of `[RSAA].bailout`, `[RSAA].endpoint` and `[RSAA].headers` that happen to be a function, which may throw an error;
223+
- `redux-api-middleware` has to call those of `[RSAA].bailout`, `[RSAA].endpoint`, `[RSAA].body`, `[RSAA].options` and `[RSAA].headers` that happen to be a function, which may throw an error;
222224
- `fetch` may throw an error: the RSAA definition is not strong enough to preclude that from happening (you may, for example, send in a `[RSAA].body` that is not valid according to the fetch specification — mind the SHOULDs in the [RSAA definition](#redux-standard-api-calling-actions));
223225
- a network failure occurs (the network is unreachable, the server responds with an error,...).
224226

@@ -577,7 +579,7 @@ The `[RSAA].method` property MUST be one of the strings `GET`, `HEAD`, `POST`, `
577579
578580
#### `[RSAA].body`
579581
580-
The optional `[RSAA].body` property SHOULD be a valid body according to the [fetch specification](https://fetch.spec.whatwg.org).
582+
The optional `[RSAA].body` property SHOULD be a valid body according to the [fetch specification](https://fetch.spec.whatwg.org), or a function. In the second case, the function SHOULD return a valid body.
581583
582584
#### `[RSAA].headers`
583585

src/middleware.js

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ function apiMiddleware({ getState }) {
3737

3838
// Parse the validated RSAA action
3939
const callAPI = action[RSAA];
40-
var { endpoint, headers, options = {} } = callAPI;
41-
const { method, body, credentials, bailout, types } = callAPI;
40+
var { endpoint, body, headers, options = {} } = callAPI;
41+
const { method, credentials, bailout, types } = callAPI;
4242
const [requestType, successType, failureType] = normalizeTypeDescriptors(
4343
types
4444
);
@@ -82,6 +82,24 @@ function apiMiddleware({ getState }) {
8282
}
8383
}
8484

85+
// Process [RSAA].body function
86+
if (typeof body === 'function') {
87+
try {
88+
body = body(getState());
89+
} catch (e) {
90+
return next(
91+
await actionWith(
92+
{
93+
...requestType,
94+
payload: new RequestError('[RSAA].body function failed'),
95+
error: true
96+
},
97+
[action, getState()]
98+
)
99+
);
100+
}
101+
}
102+
85103
// Process [RSAA].headers function
86104
if (typeof headers === 'function') {
87105
try {

test/index.js

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -984,6 +984,48 @@ test('apiMiddleware must dispatch an error request FSA when [RSAA].bailout fails
984984
actionHandler(anAction);
985985
});
986986

987+
test('apiMiddleware must dispatch an error request FSA when [RSAA].body fails', t => {
988+
const anAction = {
989+
[RSAA]: {
990+
endpoint: 'http://127.0.0.1/api/users/1',
991+
body: () => {
992+
throw new Error();
993+
},
994+
method: 'GET',
995+
types: [
996+
{
997+
type: 'REQUEST',
998+
payload: 'ignoredPayload',
999+
meta: 'someMeta'
1000+
},
1001+
'SUCCESS',
1002+
'FAILURE'
1003+
]
1004+
}
1005+
};
1006+
const doGetState = () => {};
1007+
const nextHandler = apiMiddleware({ getState: doGetState });
1008+
const doNext = action => {
1009+
t.pass('next handler called');
1010+
t.equal(action.type, 'REQUEST', 'dispatched FSA has correct type property');
1011+
t.equal(
1012+
action.payload.message,
1013+
'[RSAA].body function failed',
1014+
'dispatched FSA has correct payload property'
1015+
);
1016+
t.equal(
1017+
action.meta,
1018+
'someMeta',
1019+
'dispatched FSA has correct meta property'
1020+
);
1021+
t.ok(action.error, 'dispatched FSA has correct error property');
1022+
};
1023+
const actionHandler = nextHandler(doNext);
1024+
1025+
t.plan(5);
1026+
actionHandler(anAction);
1027+
});
1028+
9871029
test('apiMiddleware must dispatch an error request FSA when [RSAA].endpoint fails', t => {
9881030
const anAction = {
9891031
[RSAA]: {
@@ -1225,6 +1267,30 @@ test('apiMiddleware must use an [RSAA].bailout function when present', t => {
12251267
actionHandler(anAction);
12261268
});
12271269

1270+
test('apiMiddleware must use an [RSAA].body function when present', t => {
1271+
const api = nock('http://127.0.0.1')
1272+
.get('/api/users/1')
1273+
.reply(200);
1274+
const anAction = {
1275+
[RSAA]: {
1276+
endpoint: 'http://127.0.0.1/api/users/1',
1277+
body: () => {
1278+
t.pass('[RSAA].body function called');
1279+
return 'body';
1280+
},
1281+
method: 'GET',
1282+
types: ['REQUEST', 'SUCCESS', 'FAILURE']
1283+
}
1284+
};
1285+
const doGetState = () => {};
1286+
const nextHandler = apiMiddleware({ getState: doGetState });
1287+
const doNext = action => {};
1288+
const actionHandler = nextHandler(doNext);
1289+
1290+
t.plan(1);
1291+
actionHandler(anAction);
1292+
});
1293+
12281294
test('apiMiddleware must use an [RSAA].endpoint function when present', t => {
12291295
const api = nock('http://127.0.0.1')
12301296
.get('/api/users/1')

0 commit comments

Comments
 (0)