Inspired by Redux-rest and is recommended to work with Redux.
with npm
npm install redux-api --savewith bower
bower install redux-api --save=======
import reduxApi, {transformers} from "redux-api";- options - configuration rest-api endpoints
type: Object return: {reducers, actions} -
reducershave to as parameter tocreateStore(see example section). actions (seeactionssection) default: {} example: Simple endpoint definitionGET /api/v1/entrywhere response is Object
{
entry: "/api/v1/entry",
}
// equivalent
{
entry: {
url: "/api/v1/entry"
}
}
// equivalent
{
entry: {
url: "/api/v1/entry",
transformer: transformers.object, //it's default value
options: {} //it's default value
}
}
// equivalent
{
entry: {
url: "/api/v1/entry",
transformer: transformers.object, //it's default value
options: function(url, params) { //it's default value
return {};
}
}
}url - endpoint for rest api
type: String transformer - response transformer type: Function default: transformers.object example: It's a good idea to write custom transformer for example you have responce
json { "title": "Hello", "message": "World" }Custom transformerjs function customTransformer(data) { if (!data) { return {title: "", message: ""}; } return { title: (data.title || ""), message: (data.message || "")}; }options - Options for rest-api backend.function(url, options)> type: Object > default: null > example: if you use whatwg-fetch backendoptions: { method: "post", headers: { "Accept": "application/json", "Content-Type": "application/json" } }
- adaptersFetch - adapter for rest backend using
fetchAPI for rest whatwg-fetch
type: Function default: null example:
// available adapters
import adapterFetch from "redux-api/adapters/fetch";import reduxApi, {transformers} from "redux-api";
const rest = reduxApi({
entries: "/api/v1/entry",
entry: {
url: "/api/v1/entry/:id",
options: {
method: "post"
}
}
});
const {actions} = rest;
/*
initialState for store
store = {
entries: {
loading: false, // request finish flag
sync: false, // data has loaded minimum once
data: {} // data
},
entry: { loading: false, sync: false, data: {} },
}
*/
// In component with redux support (see example section)
const {dispatch} = this.props;
dispatch(rest.actions.entries()); // GET "/api/v1/entry"
dispatch(rest.actions.entry({id: 1}, {
body: JSON.stringify({ name: "Hubot", login: "hubot"
}})); // POST "/api/v1/entry/1" with body
//also available helper methods
dispatch(rest.actions.entries.reset()) // set initialState to store
dispatch(rest.actions.entries.sync()) // this mathod save you from twice requests
// flag `sync`. if `sync===true` requst
// wouldnt executeSometimes though, you might want named actions that go back to the same reducer. For example:
import reduxApi, {transformers} from "redux-api";
const rest = reduxApi({
getUser: {
reducerName: "user"
url: "/user/1", // return a user object
}
updateUser: {
reducerName: "user"
url: "/user/1/update",
options: {
method: "post"
}
}
});
const {actions} = rest;
// In component with redux support (see example section)
const {dispatch} = this.props;
dispatch(rest.actions.getUser()); // GET "/api/v1/entry"
dispatch(rest.actions.updateUser({}, {
body: JSON.stringify({ name: "Hubot", login: "hubot"})
})); // POST "/api/v1/entry/1" with bodyIn the above example, both getUser, and updateUser update the same user reducer as they share the same reducerName
For example used es7 javascript, Redux@1.0.0-rc, but it's pretty simple to migrate this code to Redux@v0.12.0
###Example rest.js
import "whatwg-fetch";
import reduxApi, {transformers} from "redux-api";
import adapterFetch from "redux-api/adapters/fetch";
export default reduxApi({
// simple edpoint description
entry: `/api/v1/entry/:id`,
// complex endpoint description
regions: {
url: `/api/v1/regions`,
// reimplement default `transformers.object`
transformer: transformers.array,
// base endpoint options `fetch(url, options)`
options: {
header: {
"Accept": "application/json"
}
}
}
}, adapterFetch(fetch)); // it's nessasary to point using rest backendindex.jsx
import React, {PropTypes} from "react";
import { createStore, applyMiddleware, combineReducers } from "redux";
import thunk from "redux-thunk";
import { Provider } from "react-redux";
import rest from "./rest"; //our redux-rest object
const createStoreWithMiddleware = applyMiddleware(thunk)(createStore);
const reducer = combineReducers(rest.reducers);
const store = createStoreWithMiddleware(reducer);
@connect((state)=> ({ entry: state.entry, regions: state.regions }))
class Application {
static propTypes = {
entry: PropTypes.object.isRequired,
regions: PropTypes.array.isRequired,
dispatch: PropTypes.func.isRequired
}
componentDidMount() {
const {dispatch} = this.props;
// fetch `/api/v1/regions
dispatch(rest.actions.regions.sync());
//specify id for GET: /api/v1/entry/1
dispatch(rest.actions.entry({id: 1}));
}
render() {
const {entry, regions} = this.props;
const Regions = regions.data.map((item)=> <p>{ item.name }</p>)
return (
<div>
Loading regions: { regions.loading }
<Regions/>
Loading entry: {entry.loading}
<div>{{ entry.data.text }}</div>
</div>
);
}
}
React.render(
<Provider store={store}>
{ ()=> <Application /> }
</Provider>,
document.getElementById("content")
);const rest = reduxApi({
user: "/user/1"
});// initialState
{
user: {
sync: false, // State was update once
syncing: false, // State syncing is in progress
loading: false, // State updating is in progress
error: null, // responce error
data: [] // responce data
}
}/api/v1/user/:id
rest.actions.user({id: 1}) // /api/v1/user/1/api/v1/user/(:id)
rest.actions.user({id: 1}) // /api/v1/user/1/api/v1/user/(:id)
rest.actions.user({id: 1, test: 2}) // /api/v1/user/1?test=2