Skip to content

Instantly share code, notes, and snippets.

@crisu83
Last active September 20, 2016 08:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save crisu83/c81c364ae4f66f0bfc93e315a2d5c72b to your computer and use it in GitHub Desktop.
Save crisu83/c81c364ae4f66f0bfc93e315a2d5c72b to your computer and use it in GitHub Desktop.
A work-in-progress implementation of an entity CRUD saga for redux-saga.
import isArray from 'lodash/isArray';
import isFunction from 'lodash/isFunction';
import isString from 'lodash/isString';
import { takeLatest } from 'redux-saga';
import { call, fork, put } from 'redux-saga/effects';
import { arrayOf, Schema } from 'normalizr';
import { callApi } from '../../api/helper';
import { normalizeEntityResponse } from '../../common/helper';
/**
* Creates an entity CRUD saga.
*
* @param {Schema} entitySchema
* @param {array} actionTypes
* @param {array} requestCreators
* @param {array} actionCreators
* @returns {Function}
*/
const createEntityCrudSaga = ({ entitySchema, actionTypes, requestCreators, actionCreators }) => {
if (!entitySchema instanceof Schema) {
throw new Error('Argument "entitySchema" must be an instance of Schema.');
}
if (!isArray(actionTypes) || actionTypes.length !== 4 || !actionTypes.map((type) => isString(type))) {
throw new Error('Argument "actionTypes" must be an array of four strings.');
}
if (!isArray(requestCreators) || requestCreators.length !== 4 || !requestCreators.map((func) => isFunction(func))) {
throw new Error('Argument "requestCreators" must be an array of four functions.');
}
if (!isArray(actionCreators) || actionCreators.length !== 3 || !actionCreators.map((func) => isFunction(func))) {
throw new Error('Argument "actionCreators" must be an array of three functions.');
}
const [createActionType, updateActionType, readActionType, deleteActionType] = actionTypes;
const [createRequestCreator, updateRequestCreator, readRequestCreator, deleteRequestCreator] = requestCreators;
const [receiveActionCreator, removeActionCreator, errorActionCreator] = actionCreators;
function* createEntity({ payload: entity }) {
try {
const { bodyAsJson } = yield call(callApi, createRequestCreator(entity));
const data = normalizeEntityResponse(bodyAsJson, entitySchema);
yield put(receiveActionCreator(data));
} catch (error) {
console.error('Failed to create entity with error: "%s"', error);
}
}
function* updateEntity({ payload: entity }) {
try {
const { bodyAsJson } = yield call(callApi, updateRequestCreator(entity));
const data = normalizeEntityResponse(bodyAsJson, entitySchema);
yield put(receiveActionCreator(data));
} catch (error) {
console.error('Failed to update entity with error: "%s"', error);
}
}
function* readEntities({ payload: params }) {
try {
const { bodyAsJson } = yield call(callApi, readRequestCreator(params));
const data = normalizeEntityResponse(bodyAsJson, arrayOf(entitySchema));
yield put(receiveActionCreator(data));
} catch (error) {
console.error('Failed to read entity with error: "%s"', error);
}
}
function* deleteEntity({ payload: id }) {
try {
const { response, bodyAsJson } = yield call(callApi, deleteRequestCreator(id));
yield put(response.status === 200
? removeActionCreator(id)
: errorActionCreator(bodyAsJson.message));
} catch (error) {
console.error('Failed to delete entity with error: "%s"', error);
}
}
function* watchCreate() {
yield* takeLatest(createActionType, createEntity);
}
function* watchUpdate() {
yield* takeLatest(updateActionType, updateEntity);
}
function* watchRead() {
yield* takeLatest(readActionType, readEntities);
}
function* watchDelete() {
yield* takeLatest(deleteActionType, deleteEntity);
}
return function*() {
yield [
fork(watchCreate),
fork(watchUpdate),
fork(watchRead),
fork(watchDelete)
];
};
};
export default createEntityCrudSaga;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment