In this section we'll see how to handle the failure case from the previous example. Let's suppose that our API function Api.fetch returns a Promise which gets rejected when the remote fetch fails for some reason.
We want to handle those errors inside our Saga by dispatching a PRODUCTS_REQUEST_FAILED action to the Store.
We can catch errors inside the Saga using the familiar try/catch syntax.
import Api from'./path/to/api'import { call, put } from'redux-saga/effects'// ...function*fetchProducts() {try {constproducts=yieldcall(Api.fetch,'/products')yieldput({ type:'PRODUCTS_RECEIVED', products }) }catch(error) {yieldput({ type:'PRODUCTS_REQUEST_FAILED', error }) }}
In order to test the failure case, we'll use the throw method of the Generator
import { call, put } from'redux-saga/effects'import Api from'...'constiterator=fetchProducts()// expects a call instructionassert.deepEqual(iterator.next().value,call(Api.fetch,'/products'),"fetchProducts should yield an Effect call(Api.fetch, './products')")// create a fake errorconsterror= {}// expects a dispatch instructionassert.deepEqual(iterator.throw(error).value,put({ type:'PRODUCTS_REQUEST_FAILED', error }),"fetchProducts should yield an Effect put({ type: 'PRODUCTS_REQUEST_FAILED', error })")
In this case, we're passing the throw method a fake error. This will cause the Generator to break the current flow and execute the catch block.
Of course, you're not forced to handle your API errors inside try/catch blocks. You can also make your API service return a normal value with some error flag on it. For example, you can catch Promise rejections and map them to an object with an error field.