Why does an empty 200 create a fail in jQuery? - javascript

I've created a simple ajax request to post some json to my api. I've done this a couple times before in other pages, but suddenly I can't get this new call to work properly.
var request = $.ajax({
type: "POST",
url: "/my-api-call",
dataType: "json",
data: JSON.stringify({"pid": 5, "comment": $('#comment').val()})
});
request.done(function(data){
console.log('weve got a succesful response!!');
})
request.fail(function(error){
console.log('weve got an error!!!');
console.log(error);
});
The call simply returns an empty 200 response, which I verify in the browser. But somehow the browser console constantly says weve got an error!!!. As you can see I also log the error, but I that is an object so full of information, that I have no idea what could be important in it. In that error object it also says the response is a plain 200 btw.
Seeing that this code is fairly simple, I can't really figure out what I'm doing wrong.
Does anybody know what I'm doing wrong here? All tips are welcome!

It's because you've set your dataType to json. So jquery is trying to parse your data (which is empty) to json. An empty result is not valid json.
"json": Evaluates the response as JSON and returns a JavaScript
object. The JSON data is parsed in a strict manner; any malformed JSON
is rejected and a parse error is thrown. As of jQuery 1.9, an empty
response is also rejected; the server should return a response of null
or {} instead. (See json.org for more information on proper JSON
formatting.)
From the docs
so you should return {} or null

Related

Console log raw data of a failed Axios get request

I would like to make an Axios get request to a private server running Flask.
In case there is an internal error in the back-end it returns an response object and an error code.:
response_object = {
"Success": False,
'error': err.message
}
return response_object, 400
The served response_object should be accessible the front-end (React.js).
axios
.get(`http://127.0.0.1:5000/data`, {
data: null,
headers: { "Content-Type": "application/json" }
})
.then(response => {
console.log(response);
})
.catch(function(error) {
console.log(error.toJSON());
});
I would expect the error to include the response object. If the URL is accessed manually in the browser the error data is visible. If there is no error in the back-end the get requests works properly.
After googling for some time I found some issues that might relate to the mentioned problem. (That is why empty data is passed in the a get request).
https://github.com/axios/axios/issues/86
https://github.com/axios/axios/issues/86
Please note that I am self taught so I might miss something obvious here. Thank you all and all the best.
I'll copy/paste my comment here so other can easily see the answer for the question
if it's a 400 status code that it's throwing (you can confirm by using the Network tab in your browser), it will fall into the catch block, the only concern is the toJSON() call... just do a simple console.log(error.message) to check if you ever get there...
I leave you a simple example so you see the catch in action
more information:
in Axios, the response text is in response.data
if you are receiving a JSON, the response.data will be automatically parsed
you do not need to pass data: null as that's the default behavior, and it's not used in a GET call (you won't pass a body in a GET call)

OData returns array instead of JSON - How to convert?

I've been trying to figure how to properly receive an OData response in Javascript for a couple of days. The problem is the response is formatted as an array instead of JSON, so the function JSON.parse(mydata) does not work with the data I am receiving.
My question is two-fold: What is the proper way to request OData to send a response as JSON and/or how do I format my current response to be JSON?
Here is the code that I am using:
$.ajax({
type: "GET",
url: requestUri,
dataType: "script",
accept: "application/json",
success: function(data, request) {
var jsonData = JSON.parse(data);
},
error: function(msg) {
alert(msg);
}})
Here is an example response of logging the variable data with console.log:
{"#odata.context":"http://localhost:5001/odata/$metadata#Movies","value":[{"Title":"Pulp Fiction","Genre":"Action","RunTime":0,"Sales":0,"Key":2}]}
The problem is the response is formatted as an array instead of JSON
It can't be. You can't send "an array" over HTTP. You have to encode it somehow … e.g. as JSON.
jQuery will, unless you override it with the dataType option, use the Content-Type HTTP response header to determine how the data is encoded. If it is JSON, it will parse the JSON.
The value of data is what you would get if you read the raw responseText and passed it through JSON.parse.
So just don't try to parse it manually. jQuery has done it for you.
Skip the step:
var jsonData = JSON.parse(data);
… and just work with data.
NB: The output of JSON.parse is an object, array or other JavaScript data type. JSON data is what you get from JSON.stringify.
If the response is in OData format, as your example shows, but you want it in JSON format that can be parsed by JSON.parse, add $format=json to the OData query, so long as the OData endpoint supports it. I know Dynamics 365 does not.
You can add it to a variable and access it just like that.
var v={"#odata.context":"http://localhost:5001/odata/$metadata#Movies","value":[{"Title":"Pulp Fiction","Genre":"Action","RunTime":0,"Sales":0,"Key":2}]};
//v.value[0] is a json object
console.log(v.value[0]);
or skip the assignment altogether and access this way:
data.value[0]
data.value[0].Genre
data.value[0].RunTime
etc....

ActionResult returns as an error in the ajax call

So, I am trying to return an xml file from my controller:
[HttpGet]
public ActionResult GetXml(int id)
{
var xmlBytes = _context.GetXml(id);
if (xmlBytes == null) return View("NotFound");
return File(new MemoryStream(xmlBytes), "application/xml", "file.xml");
}
This Action is perfectly called from this ajax call:
$.ajax({
type: 'get',
url: url,
success: function(data) {
window.location = url;
},
error: function(error) { //error.responseText contains the actual xml string!
alert("failed to download xml");
}
});
However, instead of calling success, it goes directly to the error property. One interesting thing is that the responseText property from the error object contains the xml that I am looking for.
Could someone explain me what am I doing wrong and point me in the right direction to properly download the xml stream?
Thanks
This is classic issue where the status is 200 and the responseText has the output, but it is an error. Seems strange, but there is a reason for it.
If you were to look at the responseXML you are not going to see the xml document since it can not be parsed by the browser for some reason. Now jQuery auto detects the content type and sees it is XML, it sees the responseXML as null and throws it into the error state. If you log the arguments you will see the error message.
Now to debug this you can either copy the responseText from the console or inspect the response from the network panel. Putting it into your favorite XML validator and see if it picks up the errors. Common issues is the server sticking in hidden characters into the response which chokes the parser or the server returning junk before the xml document.

Consuming JSON with an array in ExpressJS

On the webpage I am POSTing some JSON using jQuery:
$.post('/url', data);
My data is a javascript object that contains some values and an array. JSON.stringify(data) looks like:
{"favoriteAnimal":"piglet", "okayAnimals":["cats","dogs"]}
I'm consuming this JSON in a NodeJS webapp using ExpressJS (which is wired up with the body-parser middleware). I can retrieve the favorite animal like req.body.favoriteAnimal and it gives me the string piglet which is all fine and dandy.
But how do I access the values in the array?
req.body.favoriteAnimal // piglet
req.body.okayAnimals // undefined
req.body.okayAnimals[] // syntax error
This works...
req.body['okayAnimals[]']
...but smells fishy. It also won't return an array if the original data that is being POSTed contains only one element in its array (it just returns a single string).
Is there something going on with the the jQuery encoding of the JSON or something going on with the decoding in ExpressJS that's preventing me from accessing it like req.body.okayAnimals and getting an array every time?
Kevin's answer almost got me there.
$.post('/url', JSON.stringify(data)) will send a string which is one step closer. Unfortunately jQuery's $.post sets the wrong header
Content-Type:application/x-www-form-urlencoded; charset=UTF-8
which ExpressJS's body-parser will not handle appropriately. You end up with
req.body={"{\"favoriteAnimal\":\"piglet\",\"okayAnimals\":[\"cats\",\"dogs\"]}":""}
I rewrote how I was sending the data.
$.ajax({
url: '/url',
type: 'POST',
data: data,
contentType: 'application/json; charset=utf-8',
dataType: 'json'
})
I saw that my browser was sending the correct headers
Content-Type:application/json; charset=UTF-8
And observed
req.body={"favoriteAnimal":"piglet","okayAnimals":["cats","dogs"]}
JavaScript objects and JSON are two very differen things, which is the root of the problem you are seeing. What you are passing to $.post() is actually an object, not json, and is therefore being converted to a paramstring by jQuery before being sent to node. In this case, the paramstring is:
favoriteAnimal=piglet&okayAnimals[]=cats&okayAnimals[]=dogs
which of course explains why an okAnimals[] property exists on the body.
I'm surprised that the middleware you are using to parse the body isn't picking that up properly, but regardless you should instead pass a json string to $.post if you want to send it as is.
$.post('/url', JSON.stringify(data));

JSON response from Python json.dumps

I am trying to send a Django HttpResponse encoded as JSON to Javascript.
Python:
response_data = {}
response_data['status'] = 'incomplete'
return HttpResponse(json.dumps(response_data), content_type="application/json")
Jquery:
function auth_request(){
$.ajax({
url: AUTH_ENDPOINT + "myid0001",
context: document.body,
success: function(response){
console.log(response);
console.log(response.status);
if(response.status == "incomplete"){
//do something here
}
}
}
});
}
The console prints {"status": "incomplete"} for the first console log and undefined for the console.log function accessing the status element.
I tried using JSON.parse(response) but I get the error
Uncaught SyntaxError: Unexpected token a in the jquery.js file which I believe is indicating that the object is already a JSON object. However, if I check the type of the object, it displays string. How can I access the elements of the response JSON object?
You need to parse the Json back into a JS object when it's received. Otherwise, it's just text.
jQuery will do that for you if you specify dataType: "json" in the Ajax call.
I found the solution. It turns out that my Django setup was returning some additional string items so when I tried to set dataType: "json" (as #Daniel Roseman suggested) or in the jQuery function or use JSON.parse(response) I received an error. I was able to remove the extra string and it worked properly.

Categories

Resources