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);
});
Related
I'm looking for a way of handling errors with the native javascript fetch api. Used to use jQuery, but I'm trying to use more native javascript functions.
I found this blog and like the approach: https://learnwithparam.com/blog/how-to-handle-fetch-errors/
fetch(url)
.then((response) => {
if (response.status >= 200 && response.status <= 299) {
return response.json();
}
throw Error(response.statusText);
})
.then((jsonResponse) => {
// do whatever you want with the JSON response
}).catch((error) => {
// Handle the error
console.log(error);
});
However, in the catch I'm getting the statusText that belongs to the HTTP code. For 400 for example Bad request. But that is not wat I want, my call to the server will respond with exactly what is wrong. So I want to use the response body text as a the error. I tried different ways, but I can't get the response body incase the HTTP code is 400. With jQuery I used response.responseJSON.html. But this is not available with the fetch api.
So how can I can use the response body as error code.
The fetch API was designed to work best with async functions. If you can make your outer function async, your code would become:
try {
const response = await fetch(url);
if (!response.ok) {
const text = await response.text();
throw Error(text);
}
const jsonResponse = await response.json();
// do whatever you want with the JSON response
} catch (error) {
console.log(error);
}
Otherwise, it gets a bit more complicated:
fetch(url)
.then((response) => {
if (response.ok) {
return response.json();
}
return response.text().then((text) => throw Error(text));
})
.then((jsonResponse) => {
// do whatever you want with the JSON response
}).catch((error) => {
// Handle the error
console.log(error);
});
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);
});
Once that puppeteer goes to a certain url, I want that it listens to all the requests that are made, then find a specific request and return its response. The response should be a json object.
I managed in listening to all the requests and intercepting the desired one, but I don't know how to get its response. Here's my attempt: I get the error TypeError: Cannot read property 'then' of null.
Any suggestion?
page.on('request',async(request)=>{
console.log(request.url())
if (request.url().includes('desiredrequest.json')){
console.log('Request Intercepted')
request.response().then(response => {
return response.text();
}).then(function(data) {
console.log(data); // this will be a string
alert(data)
});
}
request.continue()
})
Since the response may have not arrived yet, the better method would be listening on the response event and get the request object from it.
page.on('response', async(response) => {
const request = response.request();
if (request.url().includes('desiredrequest.json')){
const text = await response.text();
console.log(text);
}
})
You might wanna use the "requestfinished" event instead of the "request" one.
page.on('requestfinished', async (request) => {
const response = await request.response();
const responseHeaders = response.headers();
let responseBody;
if (request.redirectChain().length === 0) {
// Because body can only be accessed for non-redirect responses.
if (request.url().includes('desiredrequest.json')){
responseBody = await response.buffer();
}
}
// You now have a buffer of your response, you can then convert it to string :
console.log(responseBody.toString());
request.continue()
});
I am using Promise to log the response from an api. But everytime the body is logging in as null. Most probably due to async call
For calling api from fetch.
function getDetails(url){
return new Promise((resolve, reject) => {
fetch(url, {mode: 'no-cors'}).then(res => {
resolve(res);
}, error => {
console.log(err);
})
})
}
var u = "https://get.geojs.io/v1/ip/country.json";
getDetails(u).then(function(resp){
console.log(resp);
})
I expect the response of the api in console
fetch() already returns a Promise so get rid of the new Promise(...) part
function getDetails(url) {
return fetch(...).then(...);
}
fetch() returns a Response object and not something that has already been parsed for you. You have to call .json() on it to get the response parsed by JSON.parse().
function getDetails(url) {
return fetch(url, {mode: 'no-cors'}).then(response => response.json());
}
This should already work, but with your setup will throw a syntax error:
SyntaxError: JSON.parse: unexpected end of data at line 1 column 1 of the JSON data
To get this fixed remove mode: 'no-cors'
Adding it all together will give us:
function getDetails(url) {
return fetch(url).then(response => response.json());
}
var u = "https://get.geojs.io/v1/ip/country.json";
getDetails(u).then(function(data) {
console.log(data);
})
Is this the only way to use the body.json() and also get the status code?
let status;
return fetch(url)
.then((response => {
status = response.status;
return response.json()
})
.then(response => {
return {
response: response,
status: status
}
});
This doesn't work as it returns a promise in the response field:
.then((response)=> {return {response: response.json(), status: response.status}})
Your status is not visible in the second then. You can just get the two properties in the single then.
json() returns a new Promise to you, so you need to create your object inside the then of the result of that function. If you return a Promise from a function, it will be fulfilled and will return the result of the fulfillment - in our case the object.
fetch("https://jsonplaceholder.typicode.com/posts/1")
.then(r => r.json().then(data => ({status: r.status, body: data})))
.then(obj => console.log(obj));
The .json method returns a promise, not the parsed value itself. If you want to access both the response and the parsed value in the same callback, you'll need to use nested functions like this:
fetch(url)
.then(response => {
response.json().then(parsedValue => {
// code that can access both here
})
});
Alternatively, you can use await inside an asynchronous function to eliminate the need for callbacks.
const response = await fetch(url);
const parsedValue = await response.json();
// code that can access both here
Of course, you'll want to check for errors, either with a .catch(...) call on a Promise or with a try...catch block in an async function. You could make a function that handles JSON and error cases, and then reuse it for all fetches. For example, something like this:
function handle(response) {
if (response.ok) {
return response.json().then(parsedValue => {
// the status was ok and the body could be parsed
return Promise.resolve({ response, parsedValue });
}).catch(err => {
// the status was ok but the body was empty or not JSON
return Promise.resolve({ response });
});
} else {
return response.json().catch(err => {
// the status was not ok and the body was unobtainable/empty/not JSON
throw new Error(response.statusText);
}).then(parsedValue => {
// the status was not ok and the body was JSON
throw new Error(parsedValue.error.message); // assuming an error message is returned by our REST API
});
}
}
I don't think it's the best design pattern, but hopefully this clarifies how the fetch API works.
PS: I avoided naming any variable or property json since that is the name of the text format. Once it's been parsed, it is no longer JSON.
Using two 'then's seem unnecessary to me.
async/await could get the job done pretty easily.
fetch('http://test.com/getData')
.then( async (response) => {
// get json response here
let data = await response.json();
if(data.status === 200){
// Process data here
}else{
// Rest of status codes (400,500,303), can be handled here appropriately
}
})
.catch((err) => {
console.log(err);
})
Did you try this?
return fetch(url)
.then((r)=> {return {response: r.json(), status: r.status}})
I think the cleanest way is to create a Promise.all() with the pieces you need.
.then(response => Promise.all([Promise.resolve(response.ok), response.text()]))
Which can be written shorter as
.then(response => Promise.all([response.ok, response.text()]))
The promise returns an array with all of the results
.then(data => ({ status: data[0], response: data[1] }))