I am trying to experiment with javascript on a deeper level. I am building my own $http object that has its own http methods.
var $http = {
get: function(url, success, error) {
httpHelper('GET', url, success, error);
}
};
function httpHelper(type, url, success, error) {
var xmlhttp;
xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == XMLHttpRequest.DONE ) {
if(xmlhttp.status == 200){
success(xmlhttp.responseText);
}
else if(xmlhttp.status == 400) {
error(xmlhttp.status);
}
else {
error(xmlhttp.status);
}
}
}
xmlhttp.open(type, url, true);
xmlhttp.send();
};
On the server I am returning an array of JSON objects with the request.
app.get('/api/players/', function(req, res) {
res.json([
{ name: 'Mike', points: 33 },
{ name: 'Shaq', points: 16 }
]);
});
On the client it seems I am getting a string [{"name":"Mike","points":33},{"name":"Shaq","points":16}].
How can I effectively convert the client side response to an array of JSON objects?
Just use JSON.parse
JSON.parse(xmlhttp.responseText);
Even though a comment has already answered the question, I felt I may as well throw out an actual answer (plus clarification on where to put it!)
You're looking for JSON.parse. Where you put it depends on if your $http object will only be getting JSON responses or not. If it does, then put your JSON.parse in what you send to success:
success(JSON.parse(xmlhttp.responseText));
However, if you also want to accept other types of requests, then put your JSON.parse in your callback that is success.
$http.get('some url', function(result) {
result = JSON.parse(result);
}, function() {
// ...
});
Related
I'm sending a JSON request (an applicative login but the kind of request doesn't matter) to a server with the following function:
function login() {
var payload = {
"api_key" : "", "cmd" : "login",
"params" : {}
}
payload["params"]["username"] = document.getElementById("uname").value
payload["params"]["password"] = document.getElementById("passwd").value
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://localhost:4000/api", true);
xhr.setRequestHeader("Content-type", "application/json");
xhr.setRequestHeader("Accept", "application/json");
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
resp = JSON.parse(xhr.responseText);
console.log("resp.status=" + resp.status);
console.log("resp.[\"status\"]=" + resp["status"]);
}
}
xhr.send(JSON.stringify(payload));
}
I'm actually getting the correct reply in the responseText field. For example, if the credentials are wrong, I get
{
"status": "ko",
"errors": [
{
"cmd": "login",
"long": "Login error : 'user-20' has no access to the system",
"short": "login_error"
}
]
}
If the credentials are OK I get
{
"status": "ok",
... some additional data
}
Yet, I can't manage to get the status field : resp.status or resp["status"] are always undefined. Same if the call is done in asynchroneous mode (xhr.open("POST", "http://localhost:4000/api", false);) or if I don't JSON.parse() the reply, ie: resp = xhr.responseText;.
Update - 2017.09.06
I finally found a way to get it working, but I don't quite understand why it is so. I actually changed
resp = JSON.parse(xhr.responseText);
into
resp = JSON.parse(JSON.parse(xhr.responseText));
To figure this out, I printed typeof(xhr.responseText) which is a sting. Actually typeof(JSON.parse(xhr.responseText)) is also a string and this is why it has no fields like status. Eventually, parsing xhr.responseText twice gives an object from which I actually can retrieve my data.
If somebody has a clue about what is happening, I would be interested... I don't know if this is related, but the app server that is sending the JSON is the latest version of Elixir/Phoenix, ie, 1.5/1.3 and JSON encoding/decoding is done with poison.
This is because you have assigned the resp variable to responseText
resp = JSON.parse(xhr.responseText);
To get the response code
respCode = xhr.status
Or if you want both in the same resp variable you could do
resp = {
responseText: xhr.responseText,
status: xhr.status
}
Then you can access them as resp.responseText and resp.status
I'm using angularjs to call my Rest web services but I have a problem with error handle.
This is one of my http calls:
$http({
method: 'POST',
url: "tr"+licenseSelected,//angular need string in url
headers: {'Content-Type': 'application/json'},
data : updatedLicense,
beforeSend: function() {
waitingModal.showPleaseWait();
},
complete: function() {
setTimeout(function(){
waitingModal.hidePleaseWait();
}, 1000);
}
}).then(function successCallback(response) {
if (response.data.success==true){
licenseTable.ajax.reload();
$('#updateLicenseModal').modal("hide");
notifyMessage(response.data.result, 'success');
} else {
notifyMessage(response.data.result, 'error');
}
}, function errorCallback(response) {
window.location.href = "/ATS/500";
});
I would like to show 500 page if an error occurred during http request (for example server down or wrong url), but errorCallback is never called.
Is there an error in my code? where is my fault?Thanks
This is an example of response that I can't handle in error code:
{
"status":422,
"exception":"org.springframework.web.method.annotation.MethodArgumentTypeMismatchException",
"message":"Failed to convert value of type 'java.lang.String' to required type 'java.lang.Integer'; nested exception is java.lang.NumberFormatException: For input string: \"tr71\"",
"stacktrace":"org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'java.lang.Integer'; nested exception is java.lang.NumberFormatException: For input string: \"tr71\"
at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java:115)
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:78)
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:162)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:129)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:111)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:806)
......"
}
Web service example
#Override
#RequestMapping(value = { "/license"}, method = RequestMethod.POST)
public #ResponseBody Response createLicense(#RequestBody ClientLicenseForm clientLicenseForm) {
try{
administrationService.createLicense(clientLicenseForm);
return new Response(true, true, "Your license has been created!", null);
}catch(Exception e){
ErrorResponse errorResponse= ErrorResponseBuilder.buildErrorResponse(e);
LOG.error("Threw exception in AdministrationControllerImpl::createLicense :" + errorResponse.getStacktrace());
return new Response(false,false,"Error! Your license hasn't been created!",errorResponse);
}
}
This may be the problem(it wrap json response inside another object), but how can I fix it?
UPDATE
I have fixed with this code, I'll test it
}).then(function successCallback(response) {
if (typeof response.data.success == 'undefined'){
window.location.href = "/ATS/500";
}else if (response.data.success==true){
licenseTable.ajax.reload();
$('#updateLicenseModal').modal("hide");
notifyMessage(response.data.result, 'success');
} else if(response.data.success==false) {
notifyMessage(response.data.result, 'error');
}
}, function errorCallback(response) {
window.location.href = "/ATS/500";
});
Redarding you comments you get a json response (i think with 200 header)
The error callback will not fire while in the header response was 200 code.
You can manage it in two ways:
Rewrite backend side to return proper status header code
Check if response valid in successCallback
if (response.data.exception) {
window.location.href = "/ATS/500";
}
NOTE: but basically it's wrong that server return this type or error with stacktrace.
Exceptions handling examples
I want to make a HTTP GET request from a url and it will contain the url of next webpage. I have to continue this process till I get an empty "next" url.
My code is as follows:
Parse.Cloud.define("myFunc", fucntion (request, response){
Parse.Cloud.httpRequest({
url: fb_url
}).then(function(httpResponse) {
next_url = httpResponse.data.next_url;
/******************/
// code to make another HttpRequest with next_url and iteratively
// doing it till next_url is null
response.success(httpResponse.text);
}, function(httpResponse) {
response.error("error " + httpResponse);
}
});
I tried a lot of different ways, but all in vain. Can anyone tell me how can I make another HttpRequest with the next_url and keep doing it until next_url is null.
Wrap the http invocation in a function that can be called recursively. This will return a chain of promises that make the requests until null is returned.
function keepGetting(url) {
return Parse.Cloud.httpRequest({ url:url }).then(function(httpResponse) {
nextUrl = httpResponse.data.nextUrl;
return (nextUrl === null)? httpResponse : keepGetting(nextUrl);
});
}
Parse.Cloud.define("myFunc", fucntion (request, response){
// initialize fb_url somehow
keepGetting(fb_url).then(function(result) {
response.success(result);
}, function(error) {
response.error(error);
});
});
(Careful, if the service takes too long or returns too many results before null, your parse call will timeout)
I am trying to post json to an api and its giving me the following error...
http://www.website.com/getPriceNoAuth?json=[object%20Object] 405 (Method Not Allowed)
This is the json object I am trying to send and its http resuest...
var productAttributes = {
"CostRequirements":[
{
"OriginPostcode":"BR60ND",
"BearerSize":100,
"BandwidthRequired":10,
"ProductCode":"CON-ELA",
"Term":36,
"Quantity":1
},
{
"ProductCode":"CON-ADD-IP4",
"Term":36,
"Quantity":0
},
{
"ProductCode":"CON-ADD-INT",
"Term":36,
"Quantity":0
}
]
}
this.getPrices1 = function () {
return $http.post('http://www.website.com/getPriceNoAuth?json=' + productAttributes ).
success(function(resp){
//log something here.
});
};
Does anyone see what I'm doing wrong? thank you.
$http({
url:'http://myurl.com'
method:'POST',
data:{
'json':productAttributes
}
});
ORRR if you really need to pass the data from the url stringify your json and decode it on server side
$http.post('http://myurl.com?json=' + JSON.stringify(myJson));
You're trying to post the data, but you're putting it in the url like a get parameter. Post data like this:
this.getPrices1 = function () {
return $http.post('http://www.website.com/getPriceNoAuth', {json: productAttributes} ).
success(function(resp){
//log something here.
});
};
The http header are not defined in there.. but by defaults it considers json as the content type:
$http.post('/someUrl', data).success(successCallback);
here you have to call an api, in which we have to sent data using get
method. Just use the following code and that's it. It works for me, hope it
will work for you also.
var dataObject = {
json : productAttributes
};
var responsePromise = $http.get("http://www.website.com/getPriceNoAuth", dataObject, {});
responsePromise.success(function(dataFromServer, status, headers, config) {
var outputDate=angular.fromJson(dataFromServer);
if(outputDate.status==1)
{
angular.forEach(outputDate.storelist, function(value, key) {
$scope.userstores.push({name:value.StoreName,id:value.StoreID});
});
}
});
responsePromise.error(function(data, status, headers, config) {
console.log("Error in fetching user store call!");
});
Searching for an answer for this question
I got as a result that follwing code works fine:
xhr = new XMLHttpRequest();
xhr.onreadystatechange=function()
{
if (xhr.readyState==4 && xhr.status==200)
{
response = JSON.parse(xhr.responseText);
if(typeof response =='object') {
$('#modal-spinner-seo-update').hide('slow');
jQuery.each(result, function(field, message) {
$('#seo-'+field).next('div.error-message').html(message).fadeIn('fast');
});
} else {
$('#modal-spinner-seo-update').hide('slow', function() {
$("#seo-widget-message-success").fadeIn('slow').delay(2000).fadeOut('slow');
});
}
return false;
}
};
xhr.open('GET','/metas/saveMetas?model='+model+'&f_key='+f_key+'&pagetitle='+pagetitle+'&keywords='+keywords+'&description='+description+'&niceurl='+niceurl, true );
xhr.send();
but this jQuery Version does not work.
So can anyone spot the mistake? Is there any? The jQuery AJAX version works fine on my localhost but the server it does not, but return an 403 Forbidden Error. It is a cakePHP project.
So I hope someone ca tell me whats wrong or what setting is missing.
$.ajax({
url: '/metas/saveMetas',
data: {
"model": model,
"f_key": f_key,
"pagetitle": pagetitle,
"keywords": keywords,
"description": description,
"niceurl": niceurl
},
dataType: 'json',
complete: function(){
return false;
},
success: function(result) {
if(typeof result =='object') {
$('#modal-spinner-seo-update').hide('slow');
jQuery.each(result, function(field, message) {
$('#seo-'+field).next('div.error-message').html(message).fadeIn('fast');
});
} else {
$('#modal-spinner-seo-update').hide('slow', function() {
$("#seo-widget-message-success").fadeIn('slow').delay(2000).fadeOut('slow');
});
}
return false;
}
});
Something else to think about, in addition to the dataType:
Since it's returning a 403 error, have you added the 'saveMetas' method in the $this->Auth->allow() method in the beforeFilter() of 'MetasController' of your CakePHP project?
class MetasController extends AppController {
public function beforeFilter() {
parent::beforeFilter();
$this->Auth->allow('saveMetas');
}
...
...
}
EDIT:
Since you said you have done this, do you have $this->autoRender = false; and $this->layout = 'ajax'; as well in your saveMetas function?
Lastly, since you can visit that page directly, do a pr( $this->request ) after the initial function call and visit the page without AJAX to see what it is telling you. 403 forbidden tells me it's a permissions issue.