How to handle errors in fetch() responses with Redux-Saga? How to handle errors in fetch() responses with Redux-Saga? javascript javascript

How to handle errors in fetch() responses with Redux-Saga?


Don't handle the then and error in your fetchUser method and your saga. Since you are already try/catching in your saga, you could handle it there.

Example

Saga

function* logIn(action) {  try {    const response = yield call(Api.logIn, action);    if (response.status >= 200 && response.status < 300) {      const user = yield response.json();      yield put({ type: types.LOG_IN_SUCCEEDED, user });    } else {      throw response;    }  } catch (error) {    yield put({ type: types.LOG_IN_FAILED, error });  }}

Fetch

fetchUser(action) {  const { username, password } = action.user;  const body = { username, password };  return fetch(LOGIN_URL, {    method,    headers: {      'Accept': 'application/json',      'Content-Type': 'application/json',    },    body: JSON.stringify(body)  })}

As a side note: I find fetch's api a little awkward because it returns a then-able response when you make a request. There are many libraries out there; personally I prefer axios which returns json by default.


if you want to have that if statement verifying the response status if(res.status >= 200 && res.status < 300) { you need to have it inside your first promise where res is defined, it's currently inside the resolved promise for res.json()

.then(res => {   if (res.status >= 200 && res.status < 300) {      res.json().then(json => {         return json    }  })})


If you need to make multiple API calls in one saga, the better approach is to throw errors at a fetch stage:

FETCH

export const getCounterTypes = (user) => {  const url = API_URL + `api/v4/counters/counter_types`;  const headers = {    'Authorization': user.token_type + ' ' + user.access_token,    'Accept': 'application/json'  };  const request = {      method: 'GET',      headers: headers  };  return fetch(url, request)  .then(response => {    return new Promise((resolve, reject) => {      if (response.status === 401) {        let err = new Error("Unauthorized");        reject(err);      }      if (response.status === 500) {        let err = new Error("Critical");        reject(err);      }      if ((response.status >= 200 && response.status < 300) || response.status === 400) {        response.json().then(json => {          console.log(json);          resolve(json);        });      }    });  });} 

SAGA

export function* getMainScreenInfoSaga() {  try {    const user = yield select(getUser);    const userInfo = yield select(getUserInfo);    if (userInfo) {      yield put({ type: types.NET_LOAD_USER_DATA });    } else {      yield put({ type: types.NET_INIT });    }    const info = yield all({      user: call(getInfo, user),      apartments: call(getUserApartments, user),      accounts: call(getUserAccounts, user),      counters: call(getCounters, user)    });    const ui = yield select(getUi);    if (!ui) {      yield put({ type: types.NET_LOAD_UI });      const ui = yield all({        apartmentTypes: call(getApartmentTypes, user),        serviceTypes: call(getServiceTypes, user),        counterTypes: call(getCounterTypes, user),      });      yield put({ type: types.GET_UI_SUCCESS, ui });    }    yield put({ type: types.GET_MAIN_SCREEN_INFO_SUCCESS, info });    yield put({ type: types.NET_END });  } catch (err) {    if (err.message === "Unauthorized") {      yield put({ type: types.LOGOUT });      yield put({ type: types.NET_END });    }    if (err.message === "Critical") {      window.alert("Server critical error");      yield put({ type: types.NET_END });    }  }}