Add duck file for API calls

This commit is contained in:
Kimmo Puputti 2017-02-21 20:59:18 +02:00
parent 37761e97b2
commit cec4ea15c7
3 changed files with 176 additions and 2 deletions

View file

@ -8,5 +8,6 @@ import { reducer as form } from 'redux-form';
import Auth from './Auth.duck';
import FlashNotification from './FlashNotification.duck';
import LocationFilter from './LocationFilter.duck';
import sdkReducer from './sdk.duck';
export { form, Auth, FlashNotification, LocationFilter };
export { form, Auth, FlashNotification, LocationFilter, sdkReducer as data };

172
src/ducks/sdk.duck.js Normal file
View file

@ -0,0 +1,172 @@
/* eslint-disable no-constant-condition, no-console */
import { call, put, take, fork } from 'redux-saga/effects';
import { mergeEntities } from '../util/data';
const requestAction = actionType => params => ({ type: actionType, payload: { params } });
const successAction = actionType => data => ({ type: actionType, payload: data });
const errorAction = actionType => error => ({ type: actionType, payload: error, error: true });
// ================ Action types ================ //
export const SHOW_LISTINGS_REQUEST = 'app/sdk/SHOW_LISTINGS_REQUEST';
export const SHOW_LISTINGS_SUCCESS = 'app/sdk/SHOW_LISTINGS_SUCCESS';
export const SHOW_LISTINGS_ERROR = 'app/sdk/SHOW_LISTINGS_ERROR';
export const QUERY_LISTINGS_REQUEST = 'app/sdk/QUERY_LISTINGS_REQUEST';
export const QUERY_LISTINGS_SUCCESS = 'app/sdk/QUERY_LISTINGS_SUCCESS';
export const QUERY_LISTINGS_ERROR = 'app/sdk/QUERY_LISTINGS_ERROR';
export const SEARCH_LISTINGS_REQUEST = 'app/sdk/SEARCH_LISTINGS_REQUEST';
export const SEARCH_LISTINGS_SUCCESS = 'app/sdk/SEARCH_LISTINGS_SUCCESS';
export const SEARCH_LISTINGS_ERROR = 'app/sdk/SEARCH_LISTINGS_ERROR';
export const SHOW_MARKETPLACE_REQUEST = 'app/sdk/SHOW_MARKETPLACE_REQUEST';
export const SHOW_MARKETPLACE_SUCCESS = 'app/sdk/SHOW_MARKETPLACE_SUCCESS';
export const SHOW_MARKETPLACE_ERROR = 'app/sdk/SHOW_MARKETPLACE_ERROR';
export const SHOW_USERS_REQUEST = 'app/sdk/SHOW_USERS_REQUEST';
export const SHOW_USERS_SUCCESS = 'app/sdk/SHOW_USERS_SUCCESS';
export const SHOW_USERS_ERROR = 'app/sdk/SHOW_USERS_ERROR';
// ================ Reducer ================ //
const initialState = {
// Error instance placeholders for each endpoint
showListingsError: null,
queryListingsError: null,
searchListingsError: null,
showMarketplaceError: null,
showUsersError: null,
// Database of all the fetched entities.
entities: {},
};
const merge = (state, payload) => {
const entities = mergeEntities(state.entities, payload.data);
return { ...state, entities };
};
export default function sdkReducer(state = initialState, action = {}) {
const { type, payload } = action;
switch (type) {
case SHOW_LISTINGS_REQUEST:
return { ...state, showListingsError: null };
case SHOW_LISTINGS_SUCCESS:
return merge(state, payload);
case SHOW_LISTINGS_ERROR:
console.error(payload);
return { ...state, showListingsError: payload };
case QUERY_LISTINGS_REQUEST:
return { ...state, queryListingsError: null };
case QUERY_LISTINGS_SUCCESS:
return merge(state, payload);
case QUERY_LISTINGS_ERROR:
console.error(payload);
return { ...state, queryListingsError: payload };
case SEARCH_LISTINGS_REQUEST:
return { ...state, searchListingsError: null };
case SEARCH_LISTINGS_SUCCESS:
return merge(state, payload);
case SEARCH_LISTINGS_ERROR:
console.error(payload);
return { ...state, searchListingsError: payload };
case SHOW_MARKETPLACE_REQUEST:
return { ...state, showMarketplaceError: null };
case SHOW_MARKETPLACE_SUCCESS:
return merge(state, payload);
case SHOW_MARKETPLACE_ERROR:
console.error(payload);
return { ...state, showMarketplaceError: payload };
case SHOW_USERS_REQUEST:
return { ...state, showUsersError: null };
case SHOW_USERS_SUCCESS:
return merge(state, payload);
case SHOW_USERS_ERROR:
console.error(payload);
return { ...state, showUsersError: payload };
default:
return state;
}
}
// ================ Action creators ================ //
export const showListings = requestAction(SHOW_LISTINGS_REQUEST);
export const showListingsSuccess = successAction(SHOW_LISTINGS_SUCCESS);
export const showListingsError = errorAction(SHOW_LISTINGS_ERROR);
export const queryListings = requestAction(QUERY_LISTINGS_REQUEST);
export const queryListingsSuccess = successAction(QUERY_LISTINGS_SUCCESS);
export const queryListingsError = errorAction(QUERY_LISTINGS_ERROR);
export const searchListings = requestAction(SEARCH_LISTINGS_REQUEST);
export const searchListingsSuccess = successAction(SEARCH_LISTINGS_SUCCESS);
export const searchListingsError = errorAction(SEARCH_LISTINGS_ERROR);
export const showMarketplace = requestAction(SHOW_MARKETPLACE_REQUEST);
export const showMarketplaceSuccess = successAction(SHOW_MARKETPLACE_SUCCESS);
export const showMarketplaceError = errorAction(SHOW_MARKETPLACE_ERROR);
export const showUsers = requestAction(SHOW_USERS_REQUEST);
export const showUsersSuccess = successAction(SHOW_USERS_SUCCESS);
export const showUsersError = errorAction(SHOW_USERS_ERROR);
// ================ Worker sagas ================ //
function* callEndpoint(sdkMethod, success, error, action) {
const params = action.payload.params;
try {
const response = yield call(sdkMethod, params);
yield put(success(response));
} catch (e) {
yield put(error(e));
}
}
// ================ Watcher sagas ================ //
// TODO: Think about structuring this file to avoid repetition without
// too much metaprogramming that makes the code harder to understand.
const endpoints = {
[SHOW_LISTINGS_REQUEST]: {
method: sdk => sdk.listings.show,
success: showListingsSuccess,
error: showListingsError,
},
[QUERY_LISTINGS_REQUEST]: {
method: sdk => sdk.listings.query,
success: queryListingsSuccess,
error: queryListingsError,
},
[SEARCH_LISTINGS_REQUEST]: {
method: sdk => sdk.listings.search,
success: searchListingsSuccess,
error: searchListingsError,
},
[SHOW_MARKETPLACE_REQUEST]: {
method: sdk => sdk.marketplace.show,
success: showMarketplaceSuccess,
error: showMarketplaceError,
},
[SHOW_USERS_REQUEST]: {
method: sdk => sdk.users.show,
success: showUsersSuccess,
error: showUsersError,
},
};
export function* watchSdk(sdk) {
const requestTypes = Object.keys(endpoints);
while (true) {
const action = yield take(requestTypes);
const { method, success, error } = endpoints[action.type];
yield fork(callEndpoint, method(sdk), success, error, action);
}
}

View file

@ -1,8 +1,9 @@
import { watchAuth } from './ducks/Auth.duck';
import { watchLoadListings } from './containers/SearchPage/SearchPage.duck';
import { watchSdk } from './ducks/sdk.duck';
const createRootSaga = sdk => function* rootSaga() {
yield [watchAuth(sdk), watchLoadListings(sdk)];
yield [watchAuth(sdk), watchLoadListings(sdk), watchSdk(sdk)];
};
export default createRootSaga;