Create a basic saga pattern to handle potential network errors. (#144)
* First pass at handling API failure. * Bity saga logic upgrade. * Reusable response.ok logic. Small optimization to array join. * Flow fixes. * Streamlined some error handling, moved types.
This commit is contained in:
parent
efee709d0f
commit
2616129409
|
@ -11,3 +11,14 @@ export function checkHttpStatus(response) {
|
|||
export function parseJSON(response) {
|
||||
return response.json();
|
||||
}
|
||||
|
||||
export async function handleJSONResponse(response, errorMessage) {
|
||||
if (response.ok) {
|
||||
const json = await response.json();
|
||||
return json;
|
||||
}
|
||||
if (errorMessage) {
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -1,19 +1,28 @@
|
|||
// @flow
|
||||
import { put, call } from 'redux-saga/effects';
|
||||
import type { Effect } from 'redux-saga/effects';
|
||||
|
||||
import { handleJSONResponse } from 'api/utils';
|
||||
|
||||
import { setRates } from 'actions/rates';
|
||||
import { showNotification } from 'actions/notifications';
|
||||
|
||||
import type { Yield, Return, Next } from 'sagas/types';
|
||||
|
||||
const symbols = ['USD', 'EUR', 'GBP', 'BTC', 'CHF', 'REP'];
|
||||
const symbolsURL = symbols.join(',');
|
||||
|
||||
function fetchRates(symbols) {
|
||||
return fetch(
|
||||
`https://min-api.cryptocompare.com/data/price?fsym=ETH&tsyms=${symbols.join(
|
||||
','
|
||||
)}`
|
||||
).then(r => r.json());
|
||||
}
|
||||
const fetchRates = () =>
|
||||
fetch(
|
||||
`https://min-api.cryptocompare.com/data/price?fsym=ETH&tsyms=${symbolsURL}`
|
||||
).then(response =>
|
||||
handleJSONResponse(response, 'Could not fetch rate data.')
|
||||
);
|
||||
|
||||
export default function* ratesSaga(): Generator<Effect, void, any> {
|
||||
const rates = yield call(fetchRates, symbols);
|
||||
yield put(setRates(rates));
|
||||
export default function* ratesSaga(): Generator<Yield, Return, Next> {
|
||||
try {
|
||||
const rates = yield call(fetchRates);
|
||||
yield put(setRates(rates));
|
||||
} catch (error) {
|
||||
yield put(showNotification('danger', error));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,37 +1,34 @@
|
|||
// @flow
|
||||
import { delay } from 'redux-saga';
|
||||
import { call, cancel, fork, put, take, takeLatest } from 'redux-saga/effects';
|
||||
|
||||
import { getAllRates } from 'api/bity';
|
||||
import { call, put, fork, take, cancel, cancelled } from 'redux-saga/effects';
|
||||
import type { Effect } from 'redux-saga/effects';
|
||||
|
||||
import { loadBityRatesSucceededSwap } from 'actions/swap';
|
||||
import { showNotification } from 'actions/notifications';
|
||||
|
||||
export function* loadBityRates(_action?: any): Generator<Effect, void, any> {
|
||||
try {
|
||||
while (true) {
|
||||
// TODO - BITY_RATE_REQUESTED
|
||||
// network request
|
||||
import type { Yield, Return, Next } from 'sagas/types';
|
||||
|
||||
export function* loadBityRates(_action?: any): Generator<Yield, Return, Next> {
|
||||
while (true) {
|
||||
try {
|
||||
const data = yield call(getAllRates);
|
||||
// action
|
||||
yield put(loadBityRatesSucceededSwap(data));
|
||||
// wait 5 seconds before refreshing rates
|
||||
yield call(delay, 5000);
|
||||
}
|
||||
} finally {
|
||||
if (yield cancelled()) {
|
||||
// TODO - implement request cancel if needed
|
||||
// yield put(actions.requestFailure('Request cancelled!'))
|
||||
} catch (error) {
|
||||
yield put(yield showNotification('danger', error));
|
||||
}
|
||||
yield call(delay, 5000);
|
||||
}
|
||||
}
|
||||
|
||||
export function* getBityRatesSaga(): Generator<Effect, void, any> {
|
||||
while (yield take('SWAP_LOAD_BITY_RATES_REQUESTED')) {
|
||||
// starts the task in the background
|
||||
const loadBityRatesTask = yield fork(loadBityRates);
|
||||
// wait for the user to get to point where refresh is no longer needed
|
||||
yield take('SWAP_STOP_LOAD_BITY_RATES');
|
||||
// cancel the background task
|
||||
// this will cause the forked loadBityRates task to jump into its finally block
|
||||
yield cancel(loadBityRatesTask);
|
||||
}
|
||||
// Fork our recurring API call, watch for the need to cancel.
|
||||
function* handleBityRates(): Generator<Yield, Return, Next> {
|
||||
const loadBityRatesTask = yield fork(loadBityRates);
|
||||
yield take('SWAP_STOP_LOAD_BITY_RATES');
|
||||
yield cancel(loadBityRatesTask);
|
||||
}
|
||||
|
||||
// Watch for latest SWAP_LOAD_BITY_RATES_REQUESTED action.
|
||||
export function* getBityRatesSaga(): Generator<Yield, Return, Next> {
|
||||
yield takeLatest('SWAP_LOAD_BITY_RATES_REQUESTED', handleBityRates);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
import type { Effect } from 'redux-saga/effects';
|
||||
|
||||
export type Yield = Effect | {};
|
||||
export type Return = void;
|
||||
export type Next = any;
|
Loading…
Reference in New Issue