My Spring boot Controller method:
#RequestMapping(value = "/test", method = RequestMethod.POST)
#ResponseBody
public ResponseEntity<APIResponseMessage> testMethod(#RequestBody MyPojo myPojo) {
APIResponseMessage resp = new APIResponseMessage();
try {
serviceObj.callServiceMethod(myPojo);
resp.setMessage("successfull!");
} catch (Exception e) {
resp.setMessage("failed!");
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(resp);
}
return ResponseEntity.ok(resp);
}
React action handler class has the following method:
export default (data) => (dispatch) => {
dispatch({
type: initHandler
});
fetchJSON(url, 'POST', data)
.then((json) => {
dispatch({
type: successHandler,
apiResponse: json
})
})
.catch((error) => {
dispatch({
type: failureHandler,
apiResponse: error,
apiMessage : "System encountered error. Please try again later."
})
})
}
And fetchJSON is define in one of my util classes in react as :
export const checkStatus = response => {
const hasError = (response.status < 200 || response.status >= 300)
if (hasError) {
const error = new Error("This is an error") // I want to set my message that I obtained from the controller here.
throw error
}
return response
}
export const parseJSON = response => response.json()
export const fetchJSON = (url, method, data) => {
return fetch(url, {
method: method,
headers: new Headers({
'Content-Type': 'application/json'
}),
body: JSON.stringify(data)
}).then(checkStatus).then(parseJSON);
}
I want to set the custom message that I get from my API to be set to the error object. I tried many options but couldn't make it to work.
The problem is how the Promise is being resolved, or rather, not resolved when you try to use it. Calls to 'response.json()' return a promise, during the normal flow of execution when you don't 'throw' an error, this promise is resolved, and you can work with the result.
However, when the error is thrown, you need to resolve, or '.then()' the error in the catch block.
I think this should work for you, first throw your response.text() in the checkStatus function:
if (hasError) {
throw response.json()
}
Since you are throwing an error in a Promise, the nearest catch, or rejection callback is invoked:
.catch((error) => {
dispatch({
type: failureHandler,
apiResponse: error,
apiMessage : "System encountered error. Please try again later."
})
})
'error' in this case is the unresolved Promise created by calling 'response.text()', so you can resolve this by wrapping the 'dispatch' in error.then() as follows:
.catch((error) => { // error is a Promise
error.then((e) => {
dispatch({
type: failureHandler,
apiResponse: e, // e is now the resolved value of 'response.text()'
apiMessage : "System encountered error. Please try again later."
});
});
})
There is a simplified jsfiddle of this here: https://jsfiddle.net/LLL38vea/
Related
I am trying to get the error status code that would be 413 in Axios catch block. I have tried different solutions nothing worked for me. Could you please review what is going wrong.
uploadNewDatDocuments(datId, files = [], additionalInfo = {}) {
return new Promise((resolve, reject) => {
let url = new URL(this.baseUrl + this.uploadDocument.replace('{id}', datId));
Object.keys(additionalInfo).forEach(queryParam => url.searchParams.set(queryParam, additionalInfo[queryParam]));
let formData = new FormData();
files.forEach(file => formData.append('files', file));
axios
.post(url.toString(), formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
.then(response => {
resolve(response.data);
})
.catch(error => {
console.log("error occurred")
reject(error);
}).finally(error=>{
console.log(error);
})
});
}
Here is my Action code.
export function uploadNewDocuments(datId, additionalInfo = {}, attachments = [], comment = {}) {
return dispatch => {
datService
.uploadNewDatDocuments(datId, attachments, additionalInfo)
.then(response => {
const attachmentsIds = response.map(attachment => attachment.id);
dispatch(
DatCommentActions.addDatNewComment(datId, {
...comment,
message: { ...comment.message, attachments: attachmentsIds }
})
);
})
.catch(error => {
dispatch(MessageActions.showMessage({ message: error.response.data.message }));
console.error(error);
});
};
}
413 Request Entity Too Large is not actually error, its a not successful response and catch wont fire unless there is actual error on response.
What you could do is check response.status and based on that and write own error handling.
I am using the following createAsyncThunk to delete an application in the db.
For some reason the fetch is not working. handleFetchErrors throws an Error if the response is not OK
export const handleFetchErrors = (response: Response) => {
if (!response.ok) {
throw Error(response.statusText)
}
}
export const deleteApplication = createAsyncThunk("applications/deleteApplication", async (data: any) => {
try {
const response = await fetch(`/api/application/${data.id}`, {
method: "DELETE",
headers: {
'Accept': 'application/json',
"Content-Type": "application/json",
},
});
//fixme: call still gets fulfilled although I am throwing an error
handleFetchErrors(response);
return (data.id);
} catch (e) {
console.error(e);
}
})
In my createSlice I am using these extraReducers for the upper case
.addCase(deleteApplication.fulfilled, (state, action) => {
state.status = DataFetchingStatus.succeeded
state.applications = state.applications.filter(application => application.id !== action.payload)
})
.addCase(deleteApplication.rejected, (state, action) => {
state.status = DataFetchingStatus.failed
state.error = action.payload
})
The deleteApplication.fulfilled is getting triggered instead of the deleteApplication.rejected.
Am I missing something?
The handleFetchErrors function throws an error, but this error is caught by deleteApplication and merely printed as a console message. Hence, deleteApplication.rejected is never dispatched. I suggest either (a) not catching the error; or (b) re-throwing the error in the catch block.
I know this is a basic and often recurring issue, but I am still unable to make it work.
I have the following code
handleAdd = (event: any): void => {
// ...
// create new task
try {
// send data to backend
fetch(`/api/tasks?name=${name}&priority=${priority}`, { method: 'post' })
.then(response => { if (!response.ok) {
throw new Error('error => how to get bad request message here?') } })
}
// handle exception
catch (e) {
console.log(e);
this.setState({
isError: true,
errorMessage: e.message
});
}
}
the API returns 400 with some error message
but in the browser I get
So I have two questions
Why the throw new Error() in fetch does not goes to catch(e) {} method (if the error is outside fetch function, it works well)? How to rewrite this line to get into catch method? I think it has something to do with the Promise object?
How to get the bad request message from response object?
update, working solution
fetch(`/api/tasks?name=${name}&priority=${priority}`, { method: 'post' })
.then(response => {
if (!response.ok) {
response.text().then(function (text) {
throw Error(text);
}).catch((e) => {
this.setError(e.message);
});
}
})
how to get response.text() into the Error exception?
when using promises, you can choose between chaining your promise with then/catch or using async/await.
if you are chaining promise you should chain with a catch:
handleAdd = (event: any): void => {
// send data to backend
fetch(`/api/tasks?name=${name}&priority=${priority}`, { method: 'post' })
.then(response => { if (!response.ok) {
throw new Error('error => how to get bad request message here?') } }
).catch((e) => {
console.log(e);
this.setState({
isError: true,
errorMessage: e.message
})
});
}
if you prefer you can change your function to async/await. with that you would use a try/catch block:
// mark your function as async
handleAdd = async (event: any): void => {
try {
// await your fetch response
const response = await fetch(`/api/tasks?name=${name}&priority=${priority}`, { method: 'post' })
if (!response.ok) {
throw new Error('error => how to get bad request message here?')
}
}
// handle exception
catch (e) {
console.log(e);
this.setState({
isError: true,
errorMessage: e.message
});
}
}
I'd imagine if you are not using React, it could be that you have a local or global error or warning message area, so that the
fetch
.then()
.catch(err => {
// display "try again later" here
});
But since you are using React and probably Redux, you could dispatch an action NETWORK_ERROR instead so that the reducer will create that error message "try again later":
fetch
.then()
.catch(err => {
// dispatch the action for NETWORK_ERROR here
});
try it this way and you are good to go
fetch(`/api/tasks?name=${name}&priority=${priority}`, { method: 'post' })
.then(response => { if (!response.ok) {
throw new Error('error => how to get bad request message here?') }
}).catch(error => {
// handle the error here
console.log(e);
});
I am trying to get data from an API. But the fetch result is returned as promise object. I want to return the contents from this promise to invoke react action.
let loginData = fetch(loginURL, { method : 'POST', headers : headerParams,
body: bodyParams })
.then((response) => response.json())
.then(data => {
return data['retrieve-agent'];
});
console.log('loginData ===>', loginData.agent);
return {
type: 'GET_AGENT_DETAILS',
payload: loginData
}
Make use of async-await to get the result without using a promise or else you would need to resolve the promise from the function
async fetchFunction() {
let loginData = await fetch(loginURL, { method : 'POST', headers : headerParams,
body: bodyParams })
.then((response) => response.json())
.then(data => {
return data['retrieve-agent'];
});
console.log('loginData ===>', loginData.agent);
return {
type: 'GET_AGENT_DETAILS',
payload: loginData
}
}
In my dataloader the response I get I do this :
method: 'PUT'
})
.then(response => response.json().then(json => {
response.ok ? json : Promise.reject(json)}))
.then(schematizeResponse)
On my Screen I have a button that dispatches the function and which is :
_updateValues(){
try{
//update Email
this.props.editProfile({
currentUserToken: this.props.userSession.currentUserToken,
data: {
email: this.state.newEmail
}
})
this.state.updated= true;
}
catch(e) {
this.state.updated= false;
}
When the response fails, I get :
Possible unhandled promise rejection (id:0 ) and the response body.
The editProfile that I call through props is in my controller :
function mapDispatchToProps(dispatch) {
return {
dispatch,
editProfile: bindActionCreators(editProfileRequest, dispatch)
};
}
Update :
this.props.editProfile({
currentUserToken: this.props.userSession.currentUserToken,
data: {
email: this.state.newEmail
}
})
Here i need :
try {
this.props.editProfile({
currentUserToken: this.props.userSession.currentUserToken,
data: {
email: this.state.newEmail
}
})
}
catch( error ? )
{
this.setState({failedUpdate:true})
}
How do I handle the rejection ?
You have the order wrong in your fetch. Try this:
method: 'PUT'
})
.then(response => {
if (response.ok)
return response.json()
else throw new Error('error')
.then(schematizeResponse).
catch(err => alert(err));