Tengo un escenario en el que necesito hacer varias llamadas a la API en paralelo. Por ahora, el código usa redux-saga all para hacer esto:
try { const results = yield all( someIds.map(id => call(axios.delete, `/api/somewhere/items/${id}`) ) ); console.log(results); yield put(someSuccessFunction) } catch(e) { yield put(someFailureFunction) } En el caso de que todas las llamadas sean exitosas, los results se registran correctamente como una matriz de respuestas axios, con headers , request , status , etc. Sin embargo, si falla incluso una sola llamada, el código salta al bloque catch . No tengo forma de saber qué llamada falló.
He leído Cómo manejar una variedad de solicitudes en la saga redux , pero en los ejemplos allí, parece que la respuesta aceptada es rastrear el éxito o el fracaso por llamada. Necesito saber si todas las llamadas tuvieron éxito y, de ser así, enviar una acción de éxito. Si falla alguna llamada, necesito saber cuáles fallaron y enviar una acción de falla o falla parcial. Podría verse así:
try { const results = yield all( someIds.map(id => call(axios.delete, `/api/somewhere/items/${id}`) ) ); const success = results.every(result => result.status === 200); const failure = results.every(result => result.status !== 200); const partialFailure = results.some(result => result.status === 200) && results.some(result => result.status !== 200); if (success) put(someSuccessAction); if (failure) put(someFailureAction); if (partialFailure) put(somePartialFailureAction); } catch(e) { yield put(someFailureFunction); } Pero parece que no puedo entender cómo recuperar la matriz de resultados cuando cualquier respuesta 500 nos salta al bloque catch. ¿Cuál es la mejor táctica para hacer esto?
El truco es tener un intento separado para cada solicitud y mapear los resultados exitosos o fallidos en una estructura sobre la cual luego puede ejecutar varias operaciones de matriz. Esencialmente, funciona como Promise.reflect . En este caso, podría ser algo como esto:
function* deleteById(id) { try { const result = yield call(axios.delete, `/api/somewhere/items/${id}`) if (result.status !== 200) throw new Error('Invalid status') return {v: result, status: 'fulfilled'} } catch (err) { return {e: err, status: 'rejected'} } } function* deleteSaga() { const results = yield all( someIds.map(id => call(deleteById, id)) ) const success = results.every(result => result.status === 'fulfilled') const failure = results.every(result => result.status === 'rejected') //... }He separado la solicitud por id en su propia saga para facilitar la lectura, aunque también puede ser un generador en línea.