JSON.parse() Vs. .json() - javascript

I have been working with fetch API and Promises recently and I came across .json() . Oftentimes .json() returns the same output as JSON.parse. I googled the question and the results pointed in other directions.
Example with XHR and JSON.parse:
$('#xhr').click(function(){
var XHR = new XMLHttpRequest();
XHR.onreadystatechange = function(){
if (XHR.status == 200 && XHR.readyState == 4) {
$('#quote').text(JSON.parse(XHR.responseText)[0]);
}
};
XHR.open("GET", url);
XHR.send();
});
Example with Fetch API:
$('#fetch').click(function(){
fetch(url)
.then(function(res){
return res.json();
})
.then(function(quote){
$('#quote').text(quote);
})
.catch(function(err){
handleError(err);
});
});
Could someone please explain the difference between these seemingly similar concepts ?
Thanks

Body.json() is asynchronous and returns a Promise object that resolves to a JavaScript object. JSON.parse() is synchronous can parse a string and change the resulting returned JavaScript object.

'AJAX' works with 'callbacks';
'fetch' works with 'promises'.
Use JSON.parse() to parse the response for AJAX.
Use json() to parse the response for fetch.

In my view both res.json and JSON.parse do the same functioning. Preference to res.json is given because of it's syntax.
Sharing the example for better understanding...
this.service.userFunction() //calling service
.then((res) => {
this.userdetails = JSON.parse(res._body); //use this
this.userdetails = res.json(); // or use this syntax any one
)}
.catch()
Using any of one them will provide the the complete response body and understanding of their functionality.

The json() method of the Body mixin takes a Response stream and reads it to completion. It returns a promise that resolves with the result of parsing the body text as JSON.
The JSON.parse() method parses a JSON string, constructing the JavaScript value or object described by the string.
Use JSON.parse() to parse the response for AJAX. Use json() to parse the response for fetch.

Related

Getting JSON.parse unexpected character error

I am calling API with fetch() which delivers data in JSON form.When i try to execute below code snippet in Firefox console ,first statement runs succesfully but second statement get an error as i want to convert json to object using JSON.parse() .Why this happen?Can anyone explain please.
fetch('https://www.metaweather.com/api/location/44418/').then((result)=>console.log(result));
fetch('https://www.metaweather.com/api/location/44418/').then((result)=>{console.log(JSON.parse(result.body));});
The console result:
I tried fetch('https://www.metaweather.com/api/location/44418/').then(result => {return result.json()}) .then(console.log); & it works .
Note that i am using a cors add-on to bypass the same origin policy.
The promise returned by fetch resolves into a Response object, not a string containing the body of the response.
You can see that in your screenshot!
Use the Request object's json() method to get the body of the response and parse it as JSON.
const response = await fetch('https://www.metaweather.com/api/location/44418/')
console.log(response);
const data = await response.json();
console.log(data);

Sending JSON from backend to frontend

I need some clarification on JSON objects. Inside my node backend, I receive a JSON object and after I'm done going through which key/value pairs I need, I send it off to the frontend. This is where I'm getting confused- I still need to turn that response object into json via response.json(). Why? If the backend is passing JSON, then why would I need to turn the response obj into JSON?
// test.js (node)
const testObj = {
"test1": {
"1": "Hello there"
}
}
app.get('some-route', async(req,res) =>{
res.send(testObj)
}
// front.js (React)
async someFunc(){
const response = await fetch('/some-route');
const data = await response.json(); //why?
}
Because on your front-end, the fetch API receives a buffer -- an array of bytes, which could contain any payload. It could be an image, plain text, a file, or a JSON payload.
Knowing what your back-end is going to send down, you need to receive the buffer of the data and then perform the .json() API on it, essentially asking that the buffer be interpreted as a serialized string representing a JSON object, and then having the Javascript engine evaluate (deserialize) that string into an object.
Fetch is a multi-purpose API that doesn't have any prior knowledge about the payload that the server is going to send. You are instructing it to treat the payload as JSON by using the .json() function.
Besides .json(), there are other helper methods to read and parse a variety of other possible response types; for example, .text() for plain text, .formData() for form encoded data (similar to querystring values), .blob(), and .arrayBuffer() for byte-level access to the returned data. You will use the appropriate method based on the response type that you're expecting from the API.
https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API
The response object isn't whatever you sent from the backend, it will be a Response object. That's how the Fetch API works. That Response object will have lots of metadata on it, and some methods, including .json which Takes a Response stream and reads it to completion. It returns a promise that resolves with the result of parsing the body text as JSON.
If you don't want to have to go through these two steps, just write this function.
const fetchJson = async url => {
const response = await fetch(url)
return response.json()
}
and use it like this:
async someFunc(){
const data = await fetchJson('/some-route')
}
A response object is more than just its JSON part. It contains all HTTP protocol elements, like headers, the state of the response and so on.
When you use res.json() you are telling your code to separate only the JSON part from all these other things.
To understand a bit more about an HTTP response, I suggest you to read this.
Good question!
When you send data to the front-end from the back-end, you're not just sending the data payload you created in your testObj. What's actually being returned is a response object, which will look something like:
{
type: "cors",
url: "http://some-url.com/some-api",
redirected: false,
status: 200,
ok: true,
body: ReadableStream,
...
headers: Headers,
json: json(),
...
}
where the value of response.json is the body deserializer method in the response object. You can see for yourself; try to console.log(data) from your example after removing the .json() bit, and you'll get a look at the response object in its entirety.
As you can see, the response's body - or the payload you sent from the server - is received by the client as a ReadableStream object, which then needs to be deserialized once the entire object has reached the client. The response.json() method simply deserializes the response.body ReadableStream object from serialized byte data into JSON, which you can then parse in your application.

Why can't I view json inside fetch's Response object in the developer console?

I recently learned about JavaScript's Fetch API, and am wondering why I cannot see json data directly from the Response object returned from the Fetch.
For example, I have a url that returns some json.
fetch("https://myURL/json",
{
method: "GET",
credentials: "include"
}
)
.then(function(response) {
if(response.ok) {
return response.json();
}
throw new Error('Network response was not ok.');
}).then(function(myJson) {
console.log(myJson);
})
If I put a breakpoint inside the first .then, I can view the Response object returned from the fetch in Chrome/Firefox's developer console. That object will have some data, but no way to directly view the json. I have to call that object's .json() method and return that to actually see the json data.
Why can't I see the json data inside the Response object before calling .json()? Hasn't the Fetch finished when we reach the first .then()?
according to this google developers article
The response of a fetch() request is a Stream object, which means that when we call the json() method, a Promise is returned since the reading of the stream will happen asynchronously.
MDN has some info on this as well
I don't know if you made a mistake while copy-pasting your code, but you are missing the closing quotes on the URL string.
Besides that, I tried that snippet of code and it does what it is supposed to do:
fetch("https://jsonplaceholder.typicode.com/users", {
method: "GET",
credentials: "include"
})
.then(function(response) {
if (response.ok) {
return response.json();
}
throw new Error('Network response was not ok.');
}).then(function(myJson) {
console.log(myJson);
});
https://jsfiddle.net/9s9t2968/

YQL fetch returns empty object

I'm trying to retrieve json from a domain which don't allow CORS and I don't have access to the server to allow it. I have replaced the url with googleapis as an example here.
const url = 'https://www.googleapis.com/storage/v1/b/example-bucket/o/foo%2f%3fbar';
const yUrl = 'http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20json%20where%20url%3D%22' + encodeURIComponent(url) + '%22&format=json';
fetch(yUrl)
.then(function(response){
alert(JSON.stringify(response, null, 4));
})
If we open the yUrl in browser itself, it works fine: http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20json%20where%20url%3D%22https%3A%2F%2Fwww.googleapis.com%2Fstorage%2Fv1%2Fb%2Fexample-bucket%2Fo%2Ffoo%252f%253fbar%22&format=json
However the response alerted (and thus returned) to fetch is empty.
Kindly guide me in the right direction. Thanks.
P.S. I don't want to use jQuery, would prefer JavaScript.
A fetch(…) call returns a promise containing a response object, and to get the JSON from that, you need to use the .json() method, which returns a promise containing the JSON.
So all together to see the serialized JSON data, you need to do something like this:
fetch(yUrl)
.then(response => response.json())
.then(json => JSON.stringify(json))
.then(function(json) {
alert(json);
})

Using Fetch API to Access JSON

I am trying to use fetch api to bring back some data, however am unable to map it to the console once I have retrieved it.
fetch('http://jsonplaceholder.typicode.com/users', {
method: 'GET'
}).then(function(response) {
console.log(response)
response.forEach(i => console.log(i.name));
}).catch(function(err) {
console.log(`Error: ${err}` )
});
The error i get is
response.map is not a function
so I tried to parse the response,(ie var data=JSON.parse) which did not work, with the error
SyntaxError: Unexpected token o in JSON at position 1"
Interestingly, when doing the same thing with a XMLHttp request, I was required to parse it, so I would also be interested to know why the difference between these two methods of retrieving the data.
If anyone could point me in the right direction, I would be really grateful.
The Fetch API returns a response stream in the promise. The response stream is not JSON, so trying to call JSON.parse on it will fail. To correctly parse a JSON response, you'll need to use the response.json function. This returns a promise so you can continue the chain.
fetch('http://jsonplaceholder.typicode.com/users', {
method: 'GET'
})
.then(function(response) { return response.json(); })
.then(function(json) {
// use the json
});
Understanding promises is key to using the fetch API.
At the time you're trying to parse your response and loop through it, the response is actually just a promise. In order to utilize the contents of the actual response from the request, you'll have to do some promise chaining.
fetch('http://jsonplaceholder.typicode.com/users').then(function(response) {
// response.json() returns a promise, use the same .then syntax to work with the results
response.json().then(function(users){
// users is now our actual variable parsed from the json, so we can use it
users.forEach(function(user){
console.log(user.name)
});
});
}).catch(err => console.error(err));
It appears that you might be accessing the json incorrectly. You could try calling response.json() instead.
fetch('http://jsonplaceholder.typicode.com/users', {
method: 'GET'
}).then((response) => {
response.json().then((jsonResponse) => {
console.log(jsonResponse)
})
// assuming your json object is wrapped in an array
response.json().then(i => i.forEach(i => console.log(i.name)))
}).catch((err) => {
console.log(`Error: ${err}` )
});
This example is structured to match your example, but ideally, you would return response.json() on that first .then block and proceed on the next block. Here is a similar example that proceeds on the next block.
In your particular case, you can view the Fetch API as a json aware wrapper for "XMLHttpRequest"s. Main differences being that the Fetch API is simpler, functional-like, and has convenience methods. David Walsh does a reasonable comparison in his blog post, which I recommend you take a look at. Plain "XMLHttpRequest"s just pass you whatever string was sent back from the server, it has no idea it could be JSON, and thus leaves it to the user to parse the response whatever way they see fit.

Categories

Resources