Below is code for fetch in javascript:
fetch(url + "?" + o)
.then(response => {
if (response.ok) {
resolve(response.text());
} else {
reject(response.json()); ///issue in read json data how to read json?
}
})
.then(html => {
debugger
document.getElementById('partialresult').innerHTML = html;
})
.catch(err => {
debugger
console.log("Can’t access " + url + " response. Blocked by browser?" + err)
´
document.getElementById('partialresult').innerHTML = err;
});
I need to read json if (!response.ok) i need to read the json data in catch or any where just div need to updated..
Return Json format:
{ success = false, message = "Operation failed." }
How to read json in fetch?
EDIT : server return succees in html and failure( error) in json ..html working fine and i need parse json data if failure case show in div
In the code you've shown, you're trying to use resolve and reject identifiers that haven't been declared anywhere (that you've shown).
To settle the promise returned by then from within its callback, use return to return a value (or a promise to resolve to) or throw (or a rejected promise).
In a comment you've said:
Actually server return succees in html and failure( error) in json ..i need parse json data if failure case show in div
To handle that, I think I'd convert the server's error object into an Error and throw it; see comments:
fetch(url + "?" + o)
.then(response => {
if (response.ok) {
// Read the HTML that comes with success
return response.text();
} else {
// Read the JSON that comes with the error,
// then use it as an error
return response.json()
.then(serverError => {
throw new Error(serverError.message);
});
}
})
.then(html => {
// Here, you have the HTML result
document.getElementById('partialresult').innerHTML = html;
})
.catch(err => {
// Here you have either a network error or an error
// we caught above and used to create an Error instance
document.getElementById('partialresult').innerHTML = err.message || String(err);
});
Related
I am using an API that if an internal server error occurs the details of the error are returned in JSON format.
Currently, I have the following code that can handle a successful response but in the case of an HTTP 500 response, the status text is logged in the console:
function checkStatus(response) {
if (!response.ok) {
throw new Error(response.statusText);
}
return response;
}
fetch("/api/url")
.then(checkStatus)
.then(response => response.json())
.then(data => {
// process success JSON here
})
.catch(err => {
console.log(err);
});
How would I handle the JSON that is returned in the HTTP 500 response, so the properties could be used in document.getElementById(id).innerHTML assignments?
The json contained in the reponse is always in response.json() even in case of an error 500.
In your example you are throwing an error containing only statusText.
You could instead do something like that:
function checkStatus(response) {
if (!response.ok) {
response.json().then((jsonError: any) => {
// your code to handle the json, for example:
if (error.status === 500) {
throw new HttpError('Something went wrong', jsonError);
}
}
}
return response;
}
You could for example create a new class of error that takes in a property corresponding to your jsonError:
export class HttpError extends Error {
public jsonError: any;
constructor(error: Error, jsonError: any) {
super(error.message);
this.jsonError = jsonError;
}
}
Then you could use the jsonError property in your catch() method.
Where is the JSON data stored in the fetch() response variable?
I tried examining the properties in the console by checking the headers but I don't see it there.
Where is the JSON data stored in the fetch() response variable?
Initially, it isn't. When you get the response from fetch, the body of the response hasn't been read (by the fetch part of things) yet (it may well be waiting in some buffer in the browser's ajax module, but you can't access it directly). It's waiting for you to read it via the text, json, arrayBuffer, blob, or formDatamethods.
In your case, you're presumably using json. Once you call json, the body is read into an internal buffer and parsed, then the result of parsing it is used to fulfill the promise from the json method. So at that point, it's stored within the promise object json returned, accessible by consuming the promise (and not in any other way).
To access the JSON of a response, you call json and use the resulting promise:
fetch(/*...*/)
.then(response => {
if (!response.ok) {
throw new Error("HTTP status code " + response.status);
}
return response.json();
})
.then(data => {
// Use the parsed data here
})
.catch(error => { // If you return the chain, you can leave this off
// Handle/report the error here
});
or within an async function:
const response = await fetch(/*...*/);
if (!response.ok) {
throw new Error("HTTP status code " + response.status);
}
const data = await response.json();
// Use the parsed data here
when you call fetch service, you get a response in the response object
fetch('./api/myservice')
.then(
function(response) {
if (response.status !== 200) {
console.log('Looks like there was a problem. Status Code: ' +
response.status);
return;
}
// response
response.json().then(function(data) {
console.log(data);
});
}
)
.catch(function(err) {
console.log('Fetch Error :', err);
});
I have a function in my front end app which calls my node.js backend server:
Client function:
this.geocode = (placeName) => {
const url = '/api/twitter/geocode?' + 'query=' + encodeURIComponent(placeName);
return fetch(url)
.then(processResponse)
.catch(handleError)
}
// API Helper methods
const processResponse = function (response) {
if (response.ok) {
console.log(response);
return response.json()
}
throw response;
}
const handleError = function (error) {
if (error.json) {
error.json().then(error => {
console.error('API Error:', error.message || error)
})
} else {
console.error('API Error:', error.message || error)
}
}
Server route:
app.get('/api/twitter/geocode', (req, res) => {
var parameters = {
query: req.query.query
}
Twitter.get('geo/search', parameters)
.then(response => {
console.log("RESPONSE:")
console.log(response);
// check if there is a place for the given query
if(response.date.places.length > 0){
res.send(response.data.result.places[0].bounding_box.coordinates[0][0]);
}
res.send()
})
.catch(e => res.status(500).send('Something broke!')
)
});
There is a problem when placeName is the name of a place that doesn't exist (or at least that Twitter doesn't know about). The console.log(response) in the backend shows me that such a request to the Twitter api leads to a return message without place data:
{ data:
{ result: { places: [] },
query:
{ url: 'https://api.twitter.com/1.1/geo/search.json?query=FOOBARTOWN',
type: 'search',
params: [Object] } },
resp:
/*etc...*/
As you can see, places is an empty list. This response causes a crash in my frontend. I would like to know why. Look at the error message:
const handleError = function (error) {
if (error.json) {
> error.json().then(error => {
console.error('API Error:', error.message || error)
})
} else {
And some other console outputs in the browser:
GET http://localhost:3000/api/twitter/geocode?query=FOOBARTOWN 500 (Internal Server Error) (model.js:197)
Uncaught (in promise) SyntaxError: Unexpected token S in JSON at position 0
at handleError (model.js:214)
It seems like we are getting error 500. But why? My server hasn't failed. There's no error message in the node.js console.
Also, it seems like the program ends up in handleError, and then fails to convert the error to json.
Why does it go to handleError? What's the error?
Why does it say my server failed (error 500)?
How can I make sure that if this.geocode gets an empty message, I don't crash, and return that empty message (so I can check for an empty message and act appropriately in my React.js component)?
Why does it go to handleError? What's the error?
Your server is sending a 500 status code, with Something broke! as response body.
An when you try to use res.json() on a non JSON string you get:
Uncaught SyntaxError: Unexpected token S in JSON at position 0
The line if(error.json) is not doing what you think it does. handleError is being called when response.ok is false, since you're throwing the fetch response object otherwise, in that case error argument will be a fetch response that implements Body, which has a json method, even if the body isn't a JSON, which is your case.
Your handleError can be written like this, where you will handle fetch errors and non 2xx responses.
const handleError = async function(error) {
if(error instanceof Response) {
if(error.headers.get('content-type').includes('application/json'))
error = await error.json();
else error = await error.text();
}
console.error('API Error:', error.message || error)
}
Why does it say my server failed (error 500)?
Place a console.log(e) on Twitter.get().catch and you'll find out.
Your Twitter.get().then is also wrong, since you're sending the response twice.
if(response.date.places.length > 0){
res.send(response.data.result.places[0].bounding_box.coordinates[0][0]);
}
res.send()
Should be:
if(response.date.places.length > 0)
return res.send(response/*...*/);
res.send()
The following code works well and logs to the console a fetch from a website (that outputs a simple file already in json format):
getData = url => {
fetch(url)
.then(response => {
if (response.status !== 200) {
console.log(
"Looks like there was a problem. Status Code: " + response.status
);
return; //returns undefined!
}
// Examine the text in the response
response.json().then(data => {
console.log(data);
});
})
.catch(function(err) {
console.log("Fetch Error :-S", err);
});
};
getData(urlToFetch); // logs to console the website call: a json file
I want to store that fetch's content values in a variable for later use.
So, when I change:
console.log(data);
to:
return data;
I get an undefined. Any help?
Because you .catch in your getData function if something else goes wrong your function will resolve undefined as well. If you want to log it then you need to return the error as a rejecting promise so the caller can handle the error and not get an undefined value for data when the promise resolves.
You can return Promise.reject("no 200 status code") for rejecting and return response.json() for resolve If you want to add .then(x=>console.log(x)) you still need to return something or the thing calling getData will resolve to undefined:
getData = url => {
fetch(url)
.then(response => {
if (response.status !== 200) {
console.log(
"Looks like there was a problem. Status Code: " + response.status
);
return Promise.reject(//reject by returning a rejecting promise
"Looks like there was a problem. Status Code: " + response.status
);
}
// Examine the text in the response
response.json().then(data => {
console.log(data);
return data;//still need to return the data here
});
})
.catch(function (err) {
console.log("Fetch Error :-S", err);
//return the reject again so the caller knows something went wrong
return Promise.reject(err);
});
};
getData(urlToFetch) // logs to console the website call: a json file
.then(
x=>console.log("caller got data:",x)
)
.catch(
e=>console.log("caller got error:",e)
);
You could use ES6 async-await to get this done easily:
Using async-await, your code will look like this:
function getData(url){
return new Promise((resolve, reject) => {
fetch(url)
.then(response => {
if (response.status !== 200) {
console.log(
"Looks like there was a problem. Status Code: " + response.status
);
return; //returns undefined!
}
// Examine the text in the response
response.json().then(data => {
resolve(data);
});
})
.catch(function(err) {
console.log("Fetch Error :-S", err);
reject(err)
});
})
}
// Then call the function like so:
async function useData(){
const data = await getData(urlToFetch);
// console.log(data) ===> result;
}
return; //returns undefined!
You aren't returning anything, so return by itself returns undefined unless you supply it with a value.
You need to store the promise and when you need a value, you will have to resolve it. I would change this:
// Examine the text in the response
response.json().then(data => {
console.log(data);
});
to this:
// Examine the text in the response
return response.json();
Then call getData and either resolve the promise:
getData(urlToFetch).then(data => {
// Code to use data
})
Or store the promise in the variable and use it later:
let result = getData(urlToFetch);
result.then(data => {
// so whatever with data
});
What happens here is, you are under then block. Your getData functions returns the data as soon as it call fetch. It doesn't wait for the async fetch opertion to receive callback and then call function inside then.
So the return inside then function have nothing to return to. That's why it doesn't work.
Instead you can return a promise from the getData function and call then on it to get the data. I faced a similar issue sometime ago.
An example: (not tested)
getData = url => {
new Promise(function (resolve, reject) {
fetch(url)
.then(response => {
if (response.status !== 200) {
console.log(
"Looks like there was a problem. Status Code: " + response.status
);
reject(); //returns undefined!
}
// Examine the text in the response
response.json().then(data => {
resolve(data);
});
})
.catch(function(err) {
console.log("Fetch Error :-S", err);
});
};
};
getData(urlToFetch).then(data => /*do something*/ ); // logs to console the website call: a json file
So when the data is available, you can call resolve(data) and it will invoke then method on your promise.
Hope it helps.
I have an API that includes a useful description of what went wrong when an error is raised by the server (status = 500). The description comes as part of the response text. My client code, using Aurelia, calls the api via aurelia-fetch-client using a generic method to make the call:
function callRemoteService(apiName, timeout) {
return Promise.race([
this.http.fetch(apiName),
this.waitForServer(timeout || 5000) // throws after x ms
])
.then(response => response.json() )
.catch(err => {
if (err instanceof Response) {
// HERE'S THE PROBLEM.....
err.text().then(text => {
console.log('Error text from callRemoteService() error handler: ' + text);
throw new Error(text)
});
} else if (err instanceof Error) {
throw new Error(err.message);
} else {
throw new Error('Unknown error encountered from callRemoteService()');
}
});
}
Note that I want to catch the server (fetch or timeout) errors in a consistent way, and then throw back just a simple error message to the calling view. I can invoke callRemoteService successfully, catching errors when a 500 is returned with:
callRemoteService(this.apiName, this.apiTimeout)
.then(data => {
console.log('Successfully called \'' + this.apiName +
'\'! Result is:\n' + JSON.stringify(data, null, 2));
})
.catch(err => {
console.log('Error from \'' + this.apiName + '\':',err)
});
However, I'm having trouble accessing the response text, because the fetch provides the text() method that returns a promise, and that's interfering with my otherwise happy promise chaining. The code above doesn't work, leaving me with an Uncaught (in promise) error.
Hopefully there's a good way to access that response text?
This should do the trick:
function callRemoteService(apiName, timeout = 5000) {
return Promise.race([
this.http.fetch(apiName)
.then(
r => r.json(),
r => r.text().then(text => throw new Error(text))
),
this.waitForServer(timeout)
]);
}
by the way, I like what you're doing with Promise.race- nice technique!