redux-callapi-middleware v0.6.0
redux-callapi-middleware
Redux API Middleware to make API calls in generic and declarative way. Allows to fire single or multiple API calls at once or sequentially, without dependency on fetch implementation.
Contents
- Example
- Usage and Docs
- Installation
- Create middleware
- Action creator
- Lifecycle
- Dispatched FSAs
- FAQ
- Acknowledgements
- License
Example
This is the simplest form, nothing wrong here, but take a look at create middleware and action creator sections if you need customization, its quite flexible.
Single typed action
// actions file
import { CALL_API } from `redux-callapi-middleware`;
export const callApi = () => ({
[CALL_API]: {
type: ACTION_TYPE,
endpoint: 'http://yourdomain.com/api/posts',
options: {
method: 'GET'
}
}
});
// somewhere
import { callApi } from 'actions';
dispatch(callApi());
This will dispatch request FSA before request:
{ type: ACTION_TYPE, [CALL_API_PHASE]: REQUEST }
If everything is fine it will dispatch success FSA on request response:
{
type: ACTION_TYPE,
payload: payload,
[CALL_API_PHASE]: SUCCESS
}
Otherwise it will dispatch failure FSA:
{
type: ACTION_TYPE,
payload: error,
[CALL_API_PHASE]: FAILURE
error: true
}
Different action type
// actions file
import { CALL_API } from `redux-callapi-middleware`;
export const callApi = () => ({
[CALL_API]: {
types: ['REQUEST', 'SUCCESS', 'FAILURE'],
endpoint: 'http://yourdomain.com/api/posts',
options: {
method: 'GET'
}
}
});
// somewhere
import { callApi } from 'actions';
dispatch(callApi());
This will dispatch request FSA before request:
{ type: 'REQUEST' }
If everything is fine it will dispatch success FSA on request response:
{
type: 'SUCCESS',
payload: payload
}
Otherwise it will dispatch failure FSA:
{
type: 'FAILURE',
payload: error,
error: true
}
Usage and Docs
Installation
Install
redux-callapi-middleware
through npm:$ npm install redux-callapi-middleware --save
Add middleware with redux
applyMiddleware()
:import { createStore, applyMiddleware } from 'redux'; import apiMiddleware from 'redux-callapi-middleware'; import reducers from './reducers'; const store = createStore( reducers, applyMiddleware(apiMiddleware) );
Create middleware
Middleware exposes createMiddleware
function which accepts object with callApi
function.
So you can pass any fetch implementation you wish with any response interceptors.
import { createMiddleware } from 'redux-callapi-middleware';
import fetch from 'isomorphic-fetch';
const apiMiddleware = createMiddleware({ callApi: fetch });
Or with interceptors
import { createMiddleware } from 'redux-callapi-middleware';
import fetch from 'isomorphic-fetch';
const onSuccess = (response) => {
if (!response.ok) {
throw new Error('Error');
}
return response;
}
const callApi = (url, options) => fetch(url, options).then(onSuccess);
const apiMiddleware = createMiddleware({ callApi });
Action creator
Action creator should return an object with [CALL_API]
property with batch
, endpoint
, options
and types
fields. See example.
[CALL_API].batch
An API endpoints to parallel API call. Array
of Objects
contains endpoint
and options
fields in same format as [CALL_API].endpoint
and [CALL_API].options
.
batch: [
{ endpoint1, options1 },
{ endpoint2, options2 },
],
[CALL_API].queue
An API endpoints to sequnced API calls. Array
of Functions
with all the previous responses
, should return Object
with batch
or endpoint
and options
fields. contains
endpointand
optionsfields in same format as
CALL_API.endpointand
CALL_API.options`.
endpoint1,
options1
queue: [
(action, getState, responses) => ({ endpoint2, options2 }),
(action, getState, responses) => ({
batch: [
{ endpoint3, options3 },
{ endpoint4, options4 },
],
}),
],
The first queued item will be called with responses from endpoint1
and fire one request, second will be called with both responses from endpoint1
and endpoint2
and fire two requests in parallel. And in result if everything fine SUCCESS action will be fired with all the 4 responses from all the 4 requests.
[CALL_API].endpoint
An API endpoint to call. Used if batch is not populated. String or function which receives state and returns string.
endpoint: 'someurl',
// calculate url from state
endpoint: (apiAction, state) => 'someurl',
[CALL_API].options
Request options object. Used if batch is not populated. Object or function which receives state and returns object.
It uses isomorphic-fetch
under the hood, so any valid options for fetch, like body
, credentials
, headers
and etc.
options: { 'method': 'PUT'},
// calculate options from state
options: (apiAction, state) => { 'method': 'PUT'},
[CALL_API].types
Array of actions to dispatch as middleware output. It might be strings or symbols or FSA's or functions which should return FSA's or mix of them.
So its fine to have following structure in [CALL_API].types
:
[
(action, state) => ({
type: 'REQUEST',
payload: { isFetching: true }
}),
{ type: 'SUCCESS' },
'FAILURE'
]
[CALL_API].type
Action type to dispatch as middleware output. It will be the same type for REQUEST, SUCCESS and FAILURE actions, but phase of action will be attached to an action under special [CALL_API_PHASE]
property (all the info in 0.5.0 release notes
), i.e.:
{
type: ACTION_TYPE,
[CALL_API_PHASE]: REQUEST || SUCCESS || FAILURE
}
How it works
- Checks if action has
[CALL_API]
. If no it stops and dispatches action to next middleware. - Builds request endpoint and options. There might be error handling in future.
- Dispatches to next middleware request FSA from first item of
[CALL_API].types
. - Performs API call by request params.
- Checks response status with
checkStatus
function (see create middleware). If succeed it will try to parse response withparseResponse
function (see create middleware) and will dispatch success FSA from second item of[CALL_API].types
. Otherwise, it will dispatch failure FSA from third item of[CALL_API].types
.
Dispatched FSAs
The [CALL_API].types
array can hold 4 kind of actions types:
strings
- will be converted to FSAobject
.symbols
- same as strings.object
- it should be valid FSAobject
.{ type: 'REQUEST', payload: { page: 5 } }
function
- most flexible way it will receive 3 arguments:[CALL_API]
object, state and payload. But it should return valid FSAobject
.(apiAction, state, payload) => ({ type: 'SUCCESS', payload })
Request FSA
Not receives payload as FSA property or function argument from middleware. (There is no payload at this moment)
Success FSA
Receives response as payload, it will be converted to json or text by middleware.
Failure FSA
Receives error as payload, response attached to error.response
property. FSA also have error flag set to true.
FAQ
Usage with thunk (dont forget to put api middleware after thunk in middleware chain):
import { CALL_API } from `redux-callapi-middleware`; const callApi = () => ( (dispatch, getState) => // do anything you need here return dispatch({ [CALL_API]: { types: ['REQUEST', 'SUCCESS', 'FAILURE'], endpoint: 'http://yourdomain.com/api/posts', options: { method: 'GET' } } }) )
Need a meta property in FSA?
{ [CALL_API]: { types: [{ type: 'REQUEST', meta: 'anything' }, (apiAction, state, payload) => ( { type: 'SUCCESS', payload, meta: payload.meta } ), { type: 'FAILURE', meta: 'anything' }], endpoint: 'http://yourdomain.com/api/posts', options: { method: 'GET' } } }
Need a payload function? Use
function
action type in[CALL_API].types
and build own FSA.{ [CALL_API]: { types: [ 'REQUEST', 'SUCCESS', // lets pass failure type as function (apiAction, state, error) => { // do anything you need but return FSA object const payload = formatErrorPayload(error) return { type: 'FAILURE', meta: 'anything', payload }; }], endpoint: 'http://yourdomain.com/api/posts', options: { method: 'GET' } } }
Need a
promise
as output action?
Not supported, but might work with redux-promise.
- Difference with redux-api-middleware?
- It dispatches errors only with error type
- It not dispatches "programmatic" errors, like errors on endpoint generation.
- It gives more control with functions as actions types
- Not supports promises, but take look to redux-promise.
Allows to batch API calls
Want to have base URL?
Write a wrapper around your callApi action creator.
- Want to check custom headers or have custom parse response?
- Wish to have custom error handling?
Acknowledgements
Originally inspired and extracted from Dan Abramov the real-world sample in the redux repository. Thanks to all developers and contributors.
License
The MIT License (MIT) Copyright (c) 2017 Artur Charaev
5 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
7 years ago
7 years ago
7 years ago