Where is the best place to modify backend response with redux-saga?
Asked Answered
B

3

6

I have a function that prepares the errors from backend to be easy for displaying in the components - it's named prepareErrorMessages. It accepts the response from the backend and some default error message.

So - in the saga I have this:

function* updateSomethingFlow(action) {
  try {
    const response = yield call(updateSomething, action.payload);
    if (response) {
      yield put({
        type: UPDATE_SUCCESS
      });
    }
  } catch (err) {    
    yield put({
      type: UPDATE_FAILURE,
      payload: prepareErrorMessages(err, 'Failed to update. Please, try again.')
    });
  }
}

So - am I wrong to modify the errors from the backend here?

Or is it better to do this in the reducer?

case UPDATE_FAILURE:
  nextState = {
    ...state,
    loading: false,
    errors: prepareErrorMessages(payload, 'Failed to update. Please, try again.'),
  };
break;

And also - why is it better to update there?

Bays answered 22/1, 2019 at 15:51 Comment(1)
Have a look at redux.js.org/faq/… ... tldr, both options are fine - use whatever feels more right to you. Having the transform code defined somewhere else (as you already have) is generally good approach as it allows you to quickly move the transformation from one place to another based on your needs.Lisk
R
3

Personally, I would prefer to have it in the saga because I think it is the right place of handling this kind of logic.

I prefer my reducers to only be responsible for changing state, not for data transformation.

But it is my personal opinion.

Redman answered 22/1, 2019 at 18:1 Comment(0)
I
2

Personally, I think its right to do it in the reducer.

That is where you handle the responses. Action creators should only set the payload which could be some static data or a promise.

Dont see why you cannot transform/modify the received data there.

Ingress answered 22/1, 2019 at 17:29 Comment(0)
T
0

We are using a Transformer for transforming the response getting from the Api. Transformer is the function which takes the input and provide the desired output. Designing the transformer makes the code clean and easy to test.
For example :-

function* updateSomethingFlow(action) {
  try {
    const response = yield call(updateSomething, action.payload);
    // after getting the response from the api pass through the transformer.
    const transformedResponse =apiTransformer(action.payload);
    if (response) {
      yield put({
        type: UPDATE_SUCCESS,
        data: trasnformedResponse
      });
    }
  } catch (error) {    
    yield put({
      type: UPDATE_FAILURE,
      error: error)
    });
  }
}

const apiTransformer = function(apiResponse) {
   // implement the logic. This function returns the transformed Response

 }

Using this you can move reducer free from the error. Makes the code testable and making mocks easy.

For global backend Errors make a global errorHandler using Redux Middleware, like this

const errorTracking = store => next => action => {
  if (/_FAILURE$/.test(action.type)) {
    const errorCode = parseInt(
      _.get(action, ['error', 'response', 'status'])
    )
    // this was for my use case
    if (errorCode === 403) {
     // launch an Global error handler action
      return next(ErrorHandlerAction())
    } else return next(action)
  }
  return next(action)
}

While for not genric error You can implement HOC wrap it around the component for visualisation. Thus you can have global implementation for the errors.

Tocharian answered 22/1, 2019 at 18:1 Comment(2)
What apiTransformer function should do? In your example you still use preoareErrorMessage and added apiTransformer for no reason.Redman
Please see the post againTocharian

© 2022 - 2024 — McMap. All rights reserved.