Redux API Middleman
A Redux middleware extracting the asynchronous behavior of sending API requests.
Usage:
Get Started:
- Create the middleware and put into your middleware chain:
let apiMiddleware = const store = createStore
- Use it in your action creators:
// user action const GETTING_MY_INFO = 'GETTING_MY_INFO'const GET_MY_INFO_SUCCESS = 'GET_MY_INFO_SUCCESS'const GET_MY_INFO_FAILED = 'GET_MY_INFO_FAILED' { return CALL_API: method: 'get' path: '/me' sendingType: GETTING_MY_INFO successType: GET_CONTRACTS_SUCCESS errorType: GET_MY_INFO_FAILED }
- Handle it in your reducer:
// user reducer const defaultState = {} { }
The code above would send a GET
request to http://api.myapp.com/me
,
when success, it would dispatch an action:
type: GET_CONTRACTS_SUCCESS response: the-camelized-response-body
Features:
- Async to Sync: Abstract the async nature of sending API to make it easier to implement/test
- Universal Rendering Friendly
- Support chaining(successive) API calls
- Side Effect Friendly
- Replay request optionally when failed
- Tweek request/response format when needed
API Documentation:
Creation:
A middleware can be created like this:
Options:
baseUrl
: The base url of api calls(required)
errorInterceptor
(optional):
When provided, this function would be invoked whenever an API call fails. The function signature looks like this:
{ }
Where:
err
is the error object returned by superagent
,
replay()
can be used to replay the request with the same method/parameters,
proceedError()
can be used to proceed error to reducers
For example, to refresh access token when server responds 401:
{ iferrstatus === 401 else }
The code above would do the token refreshing whenever err is 401, and proceed the original error otherwise.
generateDefaultParams
(optional):
A function which takes ({ getState })
and returns an object like this:
headers: 'x-header-key': 'header-val' query: queryKey: 'query-val' body: bodyKey: 'body-val'
On each request, the object returned by this function would be merged into the request's header
, query
, and body
, respectively.
Usage In Action Creators:
In Action Creators, we can use the following code to send a single request:
const ON_REQUEST_SUCCESS = 'ON_REQUEST_SUCCESS'const ON_REQUEST_FAILED = 'ON_REQUEST_FAILED'const ON_SENDING_REQUEST = 'ON_SENDING_REQUEST' { return extraKey: 'extra-val' CALL_API: method: 'get' path: `/users//info` successType: ON_REQUEST_SUCCESS errorType: ON_REQUEST_FAILED sendingType: ON_REQUEST_FAILED { //... } { //... } }
In short, just return an action object with CALL_API
.
Options:
method(required):
Http verb to use, can be get
, post
, put
or del
path(optional):
Request path to be concated with baseUrl
url:
Full url of request, will take precedence over path
and will ignore baseUrl
camelizeResponse(optional):
Camelize response keys of the request. default to true
Transform { user_name: 'name' }
to { userName: 'name' }
decamelizeRequest(optional):
Decamelize request payload keys. default to true
Transform { userName: 'name' }
to { user_name: 'name' }
withCredentials(optional):
Enable Access-Control requests or not. default to true
sendingType(optional):
Action type to be dispatched immediately after sending the request
successType(required):
Action type to be dispatched after the API call success
errorType(optional):
Action type to be dispatched after the API call fails
afterSuccess(optional):
A callback function to be invoked after dispatching the action with type successType
.
({ getState, dispatch, response })
would be passed into this callback function.
This is a good place to handle request-related side effects such as route pushing.
afterError(optional):
A callback function to be invoked after dispatching the action with type errorType
.
({ getState, error })
would be passed into this callback function.
Sending Chaining Requests:
To send chaining requests, just return an action with CHAIN_API
-keyed object like this:
const ON_REQUEST_SUCCESS1 = 'ON_REQUEST_SUCCESS1'const ON_REQUEST_SUCCESS2 = 'ON_REQUEST_SUCCESS2' { return CHAIN_API: { return extraKey: 'extra-val' CALL_API: method: 'get' path: `/users//info` successType: ON_REQUEST_SUCCESS1 } { return CALL_API: method: 'get' path: `/blogs/` successType: ON_REQUEST_SUCCESS2 } }
In the code above, we send an API to /users/${username}/info
to fetch user info containing a key blogId
.
After the first request is finished, we then send the second request with the blogId
returned by server.
Usage In Reducers:
During the life cycle of an API call, several types of actions would be dispatched:
sendingType
action:
After the request has been sent, an action of type sendingType
would be dispatched immediately.
The action would contain the key-val pairs other than CALL_API
in the action object.
For example, if our action object looks like this:
extraKey1: 'extra-val-1' extraKey2: 'extra-val-2' CALL_API: ...
then the sendingType
action would be:
type: sendingType extraKey1: 'extra-val-1' extraKey2: 'extra-val-2'
successType
action:
After the server responds successfully, an action of type successType
would be dispatched.
The action would contain:
- the key-val pairs other than
CALL_API
in the action object - an extra
response
key, with its value be the server response
For example, if the server responds with a body like this:
responseKey: 'response-val'
then the successType
action would be:
type: successType extraKey1: 'extra-val-1' extraKey2: 'extra-val-2' response: responseKey: 'response-val'
errorType
action:
After the server responds fails, an action of type errorType
would be dispatched.
The action would contain:
- the key-val pairs other than
CALL_API
in the action object - an extra
error
key, with its value be the error object returned byaxios
LICENCE:
MIT