redux-rest-api ![Build Status](https://travis-ci.org/restlessbit/redux-rest-api.svg?branch=master)
Middleware that gives you a uniform way to define API actions in Redux applications.
Example usage:
import { API_ACTION_TYPE } from 'redux-rest-api'
store.dispatch({
[API_ACTION_TYPE]: {
types: ['PENDING', 'SUCCESS', 'FAILURE'],
endpoint: 'https://monsterfactory.net',
fetchOptions: {
headers: {
'Content-Type': 'application/json'
},
method: 'POST',
body: JSON.stringify({
name: 'Guy Fieri'
})
}
}
}).then(() => {
console.log()('Oh no what have you done')
}).catch(() => {
console.log('Thank god')
})
Installation
npm install redux-rest-api
Usage
Add middleware to store
In order for a fetch to request to be generated whenever an API action is dispatched, the api middleware must be applied to your store.
import { apiMiddleware } from 'redux-rest-api'
import { applyMiddleware, createStore } from 'redux'
const middleware = applyMiddleware(apiMiddleware)
const store = createStore(reducers, initialState, middleware)
Now whenever an API action like this gets dispatched to the store:
import { API_ACTION_TYPE } from 'redux-rest-api'
const promise = store.dispatch({
[API_ACTION_TYPE]: {
types: ['PENDING', 'SUCCESS', 'FAILURE'],
endpoint: 'https://monsterfactory.net',
fetchOptions: { }
}
})
A fetch request will be made to the given endpoint
, and three actions with the specified types
will be dispatched while that fetch request is being made.
The
You can specify the types of these three actions by setting the types
property of the api action to an array of three strings.
The first string will be the pending
action type, the second the success
action type, and the third the failure
action type.
Pending Action
The pending
action is dispatched to the store before the fetch request is created.
{
type: ['PENDING']
}
Success action
This action will be dispatched to the store if the fetch request resolves with an OK
status code. The action's payload will contain the JSON response from the endpoint.
{
type: ['SUCCESS'],
payload: { }
}
Failure action
The failure action is dispatched to the store if the fetch request is rejected with a non-OK
status code. The payload of the action will contain the Response object from the rejected request.
{
type: ['FAILURE'],
payload: { }
}
Hook up a reducer (or write your own)
Now that you have middleware that is generating actions for you, you need to create a reducer that will handle those actions and update the store accordingly.
You can use the reducer included with redux-rest-api
to handle these actions, or you can write your own.
Using the provided reducer
Odds are the state for most of your API requests is going to look very similar:
const state = {
isPending: false,
response: null,
error: null
}
As such, redux-rest-api
provides a reducer that you can use to manage the state of multiple API requests.
Example usage
import { configureApiReducer } from 'redux-rest-api'
import { combineReducers } from 'redux'
const reducers = combineReducers({
monsters: configureApiReducer({
types: ['MONSTERS_FETCH_PENDING', 'MONSTERS_FETCH_SUCCESS', 'MONSTERS_FETCH_FAILURE']
}),
pokemon: configureApiReducer({
types: ['POKEMON_FETCH_PENDING', 'POKEMON_FETCH_SUCCESS', 'POKEMON_FETCH_FAILURE']
}),
...
})
export reducers
The initial state of the store will look like this:
{
monsters: {
isPending: false,
response: null,
error: null
},
pokemon: {
isPending: false,
response: null,
error: null
}
}
How the reducer updates state
The api reducer will handle actions from the API middleware that match the given types
.
Pending action type
The reducer will set the isPending
property to true.
{
isPending: false => true
}
Success action type
The api reducer will set the isPending
property to false
and will populate the response
field with the JSON
response from the API. error
will be set to null.
{
isPending: true => false,
response: null => { },
error: { } => null
}
Failure action type
The api reducer will set the isPending
property to false
and will populate the error
field
with the Response object from the failed fetch request.
{
isPending: true => false,
error: null => { }
}
Using your own reducer
If the provided reducer doesn't meet your needs, you can always write your own reducer to handle the actions that are dispatched by the API middleware.
Check out the source for the included reducer for an example.
Dispatching API actions
Once you have a reducer to handle the actions dispatched by the API middleware, you can start dispatching API actions.
API actions have the following properties:
types
This is an array of three strings that define the action types that will be dispatched by the API middleware.
endpoint
The url for the fetch request.
fetchOptions
An object containing the options that will be passed to the underlying fetch request, such as body
and method
.
For a full list of options you can pass to the fetch request, check out out the MDN docs.
Because the API middleware converts API actions to Promises, you can delay rendering a component until
the data that it requires has been fetched. This is super handy for server side rendering.
Here's an example of delaying rendering with React Router:
import { API_ACTION_TYPE } from 'redux-rest-api'
<Route path="/" component={SomeComponent} onEnter={(state, replace, next) => {
store.dispatch({
[API_ACTION_TYPE]: {
types: ['FIERI_DESTROY_PENDING', 'FIERI_DESTROY_SUCCESS', 'FIERI_DESTROY_FAILURE'],
endpoint: 'http://monsterfactory.net/1',
fetchOptions: {
method: 'DELETE'
}
}
}).then(() => {
next()
}).catch(() => {
next()
})
}} />
For more details on async routes in React Router, check out the React Router docs.
License
MIT