Search code examples
javascriptreduxfetch-apiredux-saga

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


I try to handle Unauthorized error from server using redux-saga. This is my saga:

function* logIn(action) {
  try {
    const user = yield call(Api.logIn, action);
    yield put({type: types.LOG_IN_SUCCEEDED, user});
  } catch (error) {
    yield put({type: types.LOG_IN_FAILED, error});
  }
}

I fetch data like this:

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)
  })
    .then(res => {
      res.json().then(json => {
        if (res.status >= 200 && res.status < 300) {
          return json
        } else {
          throw res
        }
      })
    })
    .catch(error => {throw error});
}

But anyway result is {type: 'LOG_IN_SUCCEEDED', user: undefined} when I expect {type: 'LOG_IN_FAILED', error: 'Unauthorized'}. Where is my mistake? How to handle errors right using Redux-Saga?


Solution

  • 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.