I'm pretty new to the fetch api and cant figure out why I can access response.json() locally but not once deployed.
EDIT: Just making the question clearer. When my response is NOT ok, I want to send response.json() to my errorCallBack function. This works locally and I set my error message to 'MyException'. However, when it is deployed to a new environment the parameter received by errorCallBack is a Promise with the status - 'Pending' and the catch in the errorCallBack function is hit.
Fetch:
fetch(request)
.then(response => {
if (!response.ok) {
errorCallBack(response.json());
return;
}
successCallBack();
})
.catch(error => {
console.log(error.message);
errorCallBack();
});
Error callback:
errorCallBack = (jsonResponse) => {
jsonResponse
.then(data => {
if (data) {
if (data.MyException) {
this.setErrorMessage("MyException");
return;
}
}
})
.catch(() => {
this.setErrorMessage("");
});
}
Some changes. response.json() can fail if you are returning an empty response, but you can add your logic there.
fetch(request)
.then(response => {
if (!response.ok) {
console.log(response.status) // Error code
console.log(response.statusText); // Error message
return errorCallBack(response.json()); // return response Promise
}
return successCallBack(response.json()); // This will return a Promise
})
.catch(error => {
console.log(error); // Log any error
errorCallBack(error); // return an error object
});
handle Error
errorCallBack = (response) => {
response
.then(jsonData => {
if(jsonData.myException) {
...
} else{
...
}
})
.catch(error => {
console.log(error)
...
})
}
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 got this error from my fetch api when I pass my url fetch API from a state called url. But when I changed my url into text like 'api/provinsi' I don't get any error
Error fetching data: SyntaxError: Unexpected token < in JSON at
position 0
useEffect(() => {
async function fetchMyAPI() {
await fetch(url, {
method: 'GET'
}).then(response => {
if(!response.ok) {
throw new Error(response.statusText);
}
return response.json();
})
.then(response => {
if(response.Response === 'False') {
throw new Error(response.Error);
}
setData(response.data);
}).catch(error => {
console.log("Error fetching data: ", error);
});
}
fetchMyAPI();
}, []);
And this is how I set my url state:
useEffect(() => {
if(idDaerah==1){
setColumn(['no', 'nama', 'aksi']);
setUrl('/api/provinsi');
} else if(idDaerah==2) {
setColumn(['no', 'nama', 'provinsi_id', 'aksi']);
setUrl('/api/kabupaten');
} else if(idDaerah==3) {
setColumn(['no', 'nama', 'kabupaten_id', 'aksi']);
setUrl('/api/kecamatan');
} else {
setColumn(['no', 'nama', 'kecamatan_id', 'aksi']);
setUrl('/api/desa');
}
}, []);
Because both useEffect runs at the same time, and the fetch function receive url as an empty string first time, so you need to add url as dependency.
useEffect(() => {
async function fetchMyAPI() {
await fetch(url, {
method: 'GET'
}).then(response => {
if(!response.ok) {
throw new Error(response.statusText);
}
return response.json();
})
.then(response => {
if(response.Response === 'False') {
throw new Error(response.Error);
}
setData(response.data);
}).catch(error => {
console.log("Error fetching data: ", error);
});
}
if(url !== ''){ //check if url is set i.e not an empty string
fetchMyAPI();
}
}, [url]); //add dependency, when url change then call api
OR
You can provide a default url like:
const [url, setUrl] = useState('/api/provinsi');
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 calling service that is using XML, so i want to parse XML to JSON and the JSON data set as my react state but i am getting.
TypeError: Cannot read property 'setState' of undefined
axios
.get(session_url)
.then(function(response) {
parseString(response.data, (err, result) => {
if (err) {
throw err;
} else {
this.setState({
odm: result.data,
loading: false,
});
}
});
})
.catch(function(error) {
console.log(error);
});
You're mixing and matching function()s that don't capture this and arrow (=>) functions which do.
Simply use arrow functions everywhere and the this (that's your React component) will be properly captured:
axios
.get(session_url)
.then(response => {
parseString(response.data, (err, result) => {
if (err) {
throw err;
} else {
this.setState({
odm: result.data,
loading: false,
});
}
});
})
.catch(error => {
console.log(error);
});
Better yet, if you can, use an async function:
// promisified version of `parseString`:
const parseStringP = data =>
new Promise((resolve, reject) =>
parseString(response.data, (err, result) => {
if (err) return reject(err);
resolve(result);
}),
);
// ...
try {
const response = await axios.get(session_url);
const result = await parseStringP(response.data);
this.setState({
odm: result.data,
loading: false,
});
} catch (error) {
console.log(error);
}
I have this fetch call:
api<T>(url: string, headers: Request): Promise<T> {
return fetch(url, headers)
.then(response => {
if (!response.ok) {
throw new Error(response.statusText);
}
return response.json().then(data => data as T);
})
.catch((error: Error) => {
throw error;
});
}
componentDidMount(){
this.api<Array<Response>>(url, requestData)
.then(data => {
this.setState({
jobs: data
});
})
.catch(error => {
console.error(error);
});
}
But the response that I get is a stream+json so I get invalid json at .json().
I saw that there is a library that can help me: http://oboejs.com/examples
But I'm having issues using oboe and typescript (beginner) (using https://www.npmjs.com/package/#types/oboe).
I tried:
api<T>(headers: Request): Oboe<T> {
return oboe(headers)
.done(function(response) {
return response;
})
.fail(function(error: Error) {
throw error;
});
}
componentDidMount(){
this.api<Array<Response>>(requestData)
.done(data => {
this.setState({
jobs: data
});
})
.fail(error => {
console.error(error);
});
}
But there are obvious errors as I don't know what type oboe should return so I get an error Oboe is not generic.
The error means that the Oboe class/type is not generic. Like Number of String for example
From Oboe's docs it seems that oboe(param).done() takes a callback
You can transform that call into a Promise and do the rest the same way you used to do
Replacing the callback logic with a Promise
api<T>(headers: Request): Promise<T> {
return new Promise((resolve, reject) => {
oboe(headers)
.done(data => resolve(data))
.fail(err => reject(err));
});
}
Calling it (the way you did with Promise/fetch)
componentDidMount(){
this.api<Array<Response>>(url, requestData)
.then(data => {
this.setState({
jobs: data
});
})
.catch(error => {
console.error(error);
});
}