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

后端 未结 3 1004
感动是毒
感动是毒 2020-12-15 04:46

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

function* logIn(action) {
  try {
    const user = yield call(         


        
相关标签:
3条回答
  • 2020-12-15 05:33

    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 });
        }
    
      }
    }
    
    0 讨论(0)
  • 2020-12-15 05:41

    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
        }
      })
    })
    
    0 讨论(0)
  • 2020-12-15 05:42

    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.

    0 讨论(0)
提交回复
热议问题