Reputation: 2733
I have this redux saga code where everything works okay...until the promise, after that things start to go wrong here's the relevant code
const firstApiRequest = ()=>{
return $.ajax({
url: myUrl,// ,
type:'POST',
headers: {
"Accept":"application/json",
"Content-Type":"application/json",
},
data:JSON.stringify(bodyData),
success:function(res){
console.log(res);
return res;
}
})
};
export function *startCheckout() {
try {
yield put(showLoading());
const data = yield call(firstApiRequest);//const data ends
yield put({type:FIRST_REQUEST_DONE,payload:data});
} catch (err) {
yield put(firstRequestFail(err));
}
}
export function *checkout() {
yield takeEvery(SEND_FIRST_REQUEST, startCheckout);
}
The problem is that after the return res
in firstApiRequest , I wanted to use the data
to send the FIRST_REQUEST_DONE action , but what happens is that the flow goes to FIRST_REQUEST_FAIL and shows error as true.
The problem is that the api response is coming back successfully and I am getting the data inside the error when the flow goes to FIRST_REQUEST_FAIL part of reducer and data shows up as error.
here's the code for reducer where flow goes to
case 'FIRST_REQUEST_FAIL':
return {
loading: false,
error: true,
errorMessage: action.err,
};
instead of going to
case 'FIRST_REQUEST_DONE':
return {
id: action.id,
};
so, what's wrong with the code here? why does it show error even after a succesful response from server?
Upvotes: 0
Views: 1064
Reputation: 1280
Here is an approach to handle API request using redux-saga:
First create a request helper
import 'whatwg-fetch';
function parseJSON(response) {
return response.json ? response.json() : response;
}
/**
* Checks if a network request came back fine, and throws an error if
not
*
* @param {object} response A response from a network request
*
* @return {object|undefined} Returns either the response, or throws an
* error
*/
function checkStatus(response, checkToken = true) {
if (response.status >= 200 && response.status < 300) {
return response;
}
return parseJSON(response).then(responseFormatted => {
const error = new Error(response.statusText);
error.response = response;
error.response.payload = responseFormatted;
throw error;
});
}
/**
* Requests a URL, returning a promise
*
* @param {string} url The URL we want to request
* @param {object} [options] The options we want to pass to "fetch"
*
* @return {object} The response data
*/
export default function request(url, options = {}) {
// Set headers
if (!options.headers) {
options.headers = Object.assign({
'Content-Type': 'application/json',
}, options.headers, {});
}
// Stringify body object
if (options && options.body) {
options.body = JSON.stringify(options.body);
}
return fetch(url, options)
.then(checkStatus)
.then(parseJSON)
}
In your saga
import { call, fork, put, takeLatest } from 'redux-saga/effects';
import request from 'utils/request';
import { submitSuccess, submitError } from './actions'; // path
to your actions.
import { SUBMIT } from './constants'; // The event you're listening
export function* submitData(action) {
try {
const response = yield call(request, 'your_url', { method: 'POST', body: action.body });
yield put(submitSuccess(response));
} catch(err) {
yield put(submitError(response.payload.message);
}
}
export function* defaultSaga() {
yield fork(takeLatest, SUBMIT, submitData);
}
export default defaultSaga;
Reducer
const initialState = fromJS({
submitSuccess: false,
submitReponse: '',
errorMessage: '',
});
function fooReducer(state = initialState, action) {
switch (action.type) {
case SUBMIT_SUCCESS:
return state
.update('submitSuccess', () => true)
.update('submitResponse', () => action.response);
case SUBMIT_ERROR:
return state.update('errorMessage', () => action.errorMessage);
//...
}
}
With this structure you should be able to catch your success and you error when you're making your request.
Upvotes: 0
Reputation: 2701
You shouldn't be defining the success
in your api request.
$.ajax will return a promise on its own:
const firstApiRequest = () => (
$.ajax({
url: myUrl,// ,
type:'POST',
headers:{
"Accept":"application/json",
"Content-Type":"application/json",
},
data:JSON.stringify(bodyData),
}));
Also, why are you using jQuery for making the API requests? I'd suggest using axios or fetch
Upvotes: 1