Understanding JavaScript responses - javascript

I am using the following PHP code to respond to a JavaScript fetch() request.
$json = json_encode(array(
'status' => 200,
'resources' => $dataObj
));
http_response_code(200);
header('Content-Type: application/json');
echo $json;
exit;
Back in my JavaScript code, after I get the response, I can do the following:
console.log(response.status);
console.log(response.resources);
console.log(JSON.stringify(response.resources));
The first line works and shows a value of 200. The other lines display undefined.
Now, if I add response.json() before my code, all three console lines show correctly.
let resp = await response.json();
console.log(resp.status);
console.log(resp.resources);
console.log(JSON.stringify(resp.resources));
My question is: Why in the first example can I correctly see the status of 200, but I need to use the json() function in order to see the data object?

When you make an http request - any http request - you will get back a status code. This is available on the response object.
You have also sent a status property as part of your response body, and until you explicitly tell your code to read the response body as json (response.json()) you wont be able to read any of your custom response.
So, basically, the status you can read is the one sent back by the server - not the one on your json.

If you're using the Fetch API you will always get an object back which you don't need to parse. It's already an object literal, specifically a https://developer.mozilla.org/en-US/docs/Web/API/Response.
This object has a property called status which returns 200 in your first case.
If you do however call the method json() on this object, it will parse the body of your response, not the whole thing. In this body you have your status from the backend not the status of the Response.
That's why let resp = await response.json() will return you your actual response data with your resources and such.

the response is actuallay a string:
"{'status':200,'resources':'sth'}"
and that string hasnt a resources property. You first need to parse it to an object literal.
To clear up some confusion:
The server sends a full response, so the upper is just the body , while a http response also consists of a header. If you do:
response.status
thats actually the headers status.

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);

Unexpected end of JSON input while consuming Response body (self-defined HTTP codes)

I receive the following error when attempting to consume the body of a Response to a successful HTTP POST request:
SyntaxError: Unexpected end of JSON input.
This is the Express.js statement I used to send the response:
res.status(204).send(response)
Express's res.send() method automatically converts JavaScript objects to JSON upon sending. Regardless, response is explicitly being transformed into JSON via JSON.stringify() in its definition statement. So I am definitely sending JSON.
--
I am consuming the request on the client as follows:
fetch(URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data) // data is defined elsewhere in the file
})
.then(res => res.json())
.then(data => console.log(data))
However, whenever I attempt to read response.body to completion (see Body), I receive the following error:
SyntaxError: Unexpected end of JSON input.
Again, I have already confirmed that the data I wish to send from server to client is in JSON format. So, something is going wrong in-transit, as I am attempting to convert something to JSON that is not actually JSON.
I suspect the resource I wish to send is being misplaced in-transit, but I am not sure how.
Brother, you are sending the wrong status code actually 204 is used for when no content is access due to some reason when everything is ok then 200 status code is used.
res.status(200).send(response);
updated answer after comment.
res.status(400).json({
code : 400,
message: "error message string"
})
The issue was that I was self-defining my status code as 204.
When HTTP status 204 is specified, only the headers of your request will be forwarded. No body content will be forwarded.
Recall that my original Express response was:
res.status(204).send(response)
By defining HTTP status 204, I ensured that the response in send(response) would be discarded.
My issue was resolved by updating my response to:
res.send(response)

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 php json response does not send back the data array to ajax jquery request?

I have made an ajax request to the php server where I send a data from a form request and I would to get back the same data from the server just for testing requests and responses of the same data throwing between the client and the server.
$.ajax({
method: "POST",
url: "addRaces",
dataType: "json",
data : sending_data,
success : ...
})
sending_data is an array like {field_form_name : value}
The server responds to the request with the following code :
$data = [];
foreach ($request->Input() as $key => $value) {
$data[$key] = $value;
}
return json_encode($data);
The same data should come back to the client, but nothing happen with an alert(response) or a jquery showing debug data like $('#debug').html(response);
The strange thing coming up when I try to push the server answer like
return json_encode([
'debug' => $data['name']
]);
and showing results to client like
$('#debug').html(response.debug);
it is working for a single key-value response showing the properly value field I have send from the client.
Other wise whether I send the full data as an array nothing is shown in the debug area of the client.
return json_encode($data); wont work. as it is returning the json string to the calling method which is not your jQuery at front end. Don't confuse front end (html javascript, jQuery, etc...) with back end (PHP) the two of them are running in different machines. One at client end and another at your server.
you should use echo json_encode($data); this will output the json string and your web server will send it to the front end.
Make sure you are echoing the data not returning as #bansi said, if you are echoing it already then debug using var_dump(json_encode($data)) . If json_encode() found errors it will return False instead of the expected json array.
You should debug using the developer tools instead of using code $('#debug').html(response.debug);. The Network tab of developer tools is very useful to debug HTTP requests, it will show response header and body of your requests.
In your case, just change return to echo like #bansi's answer. The return command does not print the data so you did not get anything in the response.

php custom error codes for ajax app

I have an ajax application which returns content of article with given id. All requests are sent to a php file, which takes article content from database and echos it.
Now, there is problem: php file will always have 200 OK status. And I want it to send some status code, which says that article doesn't exists. Something completely out of usual range (like 100 000 or similar).
My question is, is it possible to set some status like that with php?
You can set the HTTP status code with http_response_code. You can only use status codes in the 1xx, 2xx, 3xx, 4xx, or 5xx ranges. You can't make up your own status codes. See this answer for info on that: https://stackoverflow.com/a/11871377
For a status of "article doesn't exist", you can simply use 404 Not Found.
http_response_code(404);
Here is a list of HTTP status codes: http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
EDIT: http_response_code only works on PHP 5.4+. If you don't have PHP 5.4 you can do:
header("HTTP/1.0 404 Not Found", TRUE, 404);
More info on this: https://stackoverflow.com/a/12018482
You could send a 404 status code back using http_response_code.
Another option would be to encode a status code and the data you want to return as a JSON response and return that to the browser.
$response = array(
'status' => 100001,
'result' => '<h1>Title...'
);
echo json_encode($response);
exit;
Generally you can mix two ways of answering in PHP. Best practice is to send correct http status code , but with correct code (like 404 for not found and 409 for wrong input (just example)) you can send text response message like if it is standard answer.
So you can mix previous answers (if you need it):
http_response_code(404);
$response = array(
'status' => 100001,
'result' => 'Document was not found on server'
);
echo json_encode($response);
exit;
But i'm not sure you need sub-statuses in that situation.
With that in your javascript you can operate by xhr response code to determine the error itself and show to user some text and substatus that came from server in response body;

Categories

Resources