rra
redux-rest-adapter
npm i redux-rest-adapter
rra

redux-rest-adapter

REST adapter for redux

by Maksim Chekrishov

2.0.7 (see all)License:ISCTypeScript:Not Found
npm i redux-rest-adapter
Readme

redux-rest-adapter

npm version Code Climate Test Coverage

redux-rest-adapter is a tool for easy connection your REST api with redux store.

Compatible with json.api specification

Main points

  • Write code instead of reducers and actions for trivial data operations.

Changelog

Starts from v2.0.0 redux-rest-adapter based on axios and promise-middleware for easy access to promises and better experience with isomorphic app.

Versions 1.x.x

short-example.js

import EntityApi, {promiseMiddleware} from 'redux-rest-adapter';
import {createStore, applyMiddleware, combineReducers} from 'redux';

    const tagsApi = new EntityApi({
      entityName: 'TAG',
      endpointUrl: 'api/v2/tags'
    });

    const apiReducer = combineReducers({
      TAG: tagsApi.configureReducer()
    });

    const store = createStore(
      combineReducers({
        api: apiReducer
      }),
      {},
      applyMiddleware(promiseMiddleware())
    );

    store.dispatch(tagsApi.actions.load()).then(()=> {
        console.log(store.getState().api.TAG.data); // [{id:1, name:'tag1'}, {id:2, name:'tag2'}];
    })

Setup

your/known-entities-api.js

import EntityApi from 'redux-rest-adapter';

export const KnownEntitiesUrls = {
  NEWS_TAGS: 'news-tags',
  NEWS_TAG_FOR_EDIT: 'news-tags',
  //..
};
export default _.mapValues(KnownEntitiesUrls, (url, name) => new EntityApi({
  entityName: name,
  endpointUrl: 'api/v2/' + url
}));

your/api-reducer.js

import knownEntitiesApi from 'your/known-entities-api';

// Ability to extend default api reducers
const apiReducersExtensions = {
  NEWS_TAGS: tagsReducer
}

const apiReducers = _.mapValues(knownEntitiesApi, (api, key) => api.configureReducer(apiReducersExtensions[key]));

export default combineReducers(apiReducers);

your/index-reducer.js

import apiReducer from 'your/api-reducer';

export default combineReducers({
  api: apiReducer
  //..
});

your/configure-store.js

import indexReducer from 'your/index-reducer';
import {promiseMiddleware} from 'redux-rest-adapter';
//..
export default function configureStore(initialState) {
  return createStore(
    indexReducer,
    initialState,
    applyMiddleware(promiseMiddleware())
  );
}

your/entities-actions.js

import knownEntitiesApi from 'your/known-entities-api';

export default _.mapValues(knownEntitiesApi, entityApi => entityApi.actions);

Adapter is ready

Image devTools

Usage

Actions

import entitesActions from 'your/entities-actions';

dispatch(entitesActions.NEWS_TAG.load());                          // GET:    api/v2/news-tags
dispatch(entitesActions.NEWS_TAG.load(1));                         // GET:    api/v2/news-tags/1

// --- NOTE: HTTP methods for create and update operations can be configured
dispatch(entitesActions.NEWS_TAG.update(1, {name: 'new tag'}));    // PATCH:  api/v2/news-tags/1
dispatch(entitesActions.NEWS_TAG.create({name: 'new tag'}));       // POST:   api/v2/news-tags
dispatch(entitesActions.NEWS_TAG.remove(1));                       // DELETE: api/v2/news-tags/1

// --- Silent methods for changing store without sync with backend
dispatch(entitesActions.NEWS_TAG.set({name: 'new tag'}));          // set new data
dispatch(entitesActions.NEWS_TAG.reset());                         // reset to initial state

React component example

import entitesActions from 'your/entities-actions';

class TagsComponent extends Component {
  componentWillMount() {
    this.props.loadList();
  }

  //..

  componentWillUnmount() {
    this.props.resetEntryForEdit();
  }

  onTagFormSubmit = ()=> {
    const data = this.props.tagForEdit;
    if (data.id) {
      this.props.updateTag(data.id, data);
    } else {
      this.props.createTag(data);
    }
  }

  render() {
    return (
      this.props.pending ?
        <Loading/> :
        <div>
           {/*...*/}
        </div>
    );
  }
}

const mapStateToProps = (state) => ({
  list: state.api.NEWS_TAGS.data || [],
  pending: state.api.NEWS_TAGS._pending,
  tagForEdit: state.api.NEWS_TAG_FOR_EDIT.data || {}
});

const mapDispatchToProps = {
  createTag: entitiesActions.NEWS_TAG_FOR_EDIT.create,
  updateTag: entitiesActions.NEWS_TAG_FOR_EDIT.update,
  resetEntryForEdit: entitiesActions.NEWS_TAG_FOR_EDIT.reset,
  loadList: entitiesActions.NEWS_TAGS.load
};

const TagsContainer = connect(mapStateToProps, mapDispatchToProps)(TagsComponent);

export {TagsComponent, TagsContainer};

Configuration

EntityApi constructor options

NameTypeDefaultDescription
entityNameStringRequired. will be used for naming state and actionTypes.
endpointUrl`StringRequired. endpointUrl
reducersBuilderCustomObjectreducersBuilderDefaultCustomer can redefine interface of reducers-builder.js
axiosConfigObject{}axios config
resourceKeyString'data'Name of data property key at response object
idKeyString'id'Name of id property key at response data object. Required for CRUD reducer extensions
restHttpMethodsObject{create:'post', update:'patch'}Customer can change HTTP methods used for create and update actions

TODO

Example of generated list reducer (basic CRUD operations)

See also

redux-localstorage-adapter

Downloads/wk

3

GitHub Stars

13

LAST COMMIT

5yrs ago

MAINTAINERS

1

CONTRIBUTORS

1

OPEN ISSUES

1

OPEN PRs

0
VersionTagPublished
2.0.7
latest
6yrs ago
No alternatives found
No tutorials found
Add a tutorial
No dependencies found

Rate & Review

100
No reviews found
Be the first to rate