@oliasoft-open-source/api-middleware
v1.0.1
Published
Type-safe Redux middleware for making HTTP requests
Readme
Redux API Middleware
Shared Redux middleware for making HTTP requests.
Optional application-specific authentication and lifecycle actions can be injected when the middleware is added to the store. UI behavior remains in the consumer:
import { configureStore } from '@reduxjs/toolkit';
import { createAPIMiddleware } from '@oliasoft-open-source/api-middleware';
import { getAccessToken } from './get-access-token';
import { toasterMessageAdded } from './toasters';
const store = configureStore({
reducer,
middleware: (getDefaultMiddleware) => {
return getDefaultMiddleware().concat(
createAPIMiddleware({
getAccessToken,
globalOnErrorToastAction: ({ name, message }) => {
return toasterMessageAdded({
type: 'Error',
icon: true,
content: name,
details: message,
});
},
globalOnSuccessToastAction: ({ message }) => {
return toasterMessageAdded({
type: 'Success',
icon: true,
content: message,
});
},
}),
);
},
});Usage
API calls use the exported apiCallBegan action:
import { apiCallBegan } from '@oliasoft-open-source/api-middleware';
dispatch(
apiCallBegan({
url: '/api/wells',
method: 'GET',
onSuccess: wellsReceived.type,
}),
);The Redux API middleware handles the action as follows:
apiCallBegan(action)
│
▼
[optional] onStart
│
▼
fetch() request
│
▼
┌───────────────┬────────────────┐
│ │ │
▼ ▼ ▼
SUCCESS HTTP ERROR JS ERROR
response.ok !response.ok exception
│ │ │
▼ ▼ ▼
apiCallSuccess apiCallFailed apiCallFailed
│ │ │
├─ toast [opt] ├─ toast [opt] ├─ toast [opt]
│ │ │
│ ▼ ▼
│ [optional] [optional]
│ onError onError
│
▼
[optional] onSuccessapiCallSuccess or apiCallFailed is always dispatched. Lifecycle callbacks
are optional.
Callbacks
A callback can be a Redux action type string, an action creator, a thunk, or a
function used for another side effect. Action type strings and action creator
results are dispatched. Thunks receive dispatch and getState.
Action type callbacks:
dispatch(
apiCallBegan({
url: '/example',
method: 'GET',
onStart: exampleRequested.type,
onSuccess: exampleReceived.type,
onError: exampleRequestFailed.type,
}),
);Action creator callbacks:
dispatch(
apiCallBegan({
url: '/example',
method: 'GET',
onSuccess: (payload) => {
return exampleReceived(payload);
},
}),
);Thunk callbacks:
dispatch(
apiCallBegan({
url: '/example',
method: 'GET',
onSuccess: (data) => {
return (dispatch) => {
dispatch(exampleReceived(data));
dispatch(otherAction(data));
};
},
}),
);Request and toast options
dispatch(
apiCallBegan({
baseUrl: 'https://api.example.com',
url: '/example',
method: 'POST',
headers: { 'Content-Type': 'application/json' },
toastOnError: true,
toastOnSuccess: true,
toastOnSuccessMessage: 'Example saved',
}),
);Requirements
- Node.js 26.5.0
- pnpm 11.17.0
Development
Install dependencies:
pnpm installRun all checks:
pnpm testBuild the package:
pnpm buildReleases
Merge request pipelines can publish a prerelease with the beta npm dist-tag:
- add the
Betalabel to the merge request; - include
[Beta]in the merge request title; or - start the
beta_releasejob manually.
Stable versions are published automatically from the default branch. The version in
package.json must not already have a corresponding Git tag.
Acknowledgements
Loosely inspired by ideas from Mosh Hamedani's Ultimate Redux Course.
