I can't to process response to a jsonp request - javascript

I have url http://translate.google.ru/translate_a/t?client=x&text=enter text&sl=en&tl=pl
If you will go through this link in response you will have js file
with text:
{"sentences":[{"trans":"wprowadzania tekstu","orig":"enter text","translit":"","src_translit":""}],"src":"en","server_time":80}
I created ajax request
function GoogleTranslateItem(sourceText, langFrom, langTo) {
$.ajax({
url: 'http://translate.google.ru/translate_a/t',
data: { client: "x", text: sourceText, sl: langFrom, tl: langTo },
dataType: 'jsonp',
jsonpCallback: "getData",
success: function (data) {
alert("Success");
}
});
function getData(data) {
var dataJson = data;
alert('bingo');
}
when the answer comes from server. I can't to process it
in browser shows js error.
Syntax error at line 1 while loading:
{"sentences":[{"trans":"вход вых
------------^
expected ';', got ':'
Linked script compilation
How can i process this response?

I think you should take a look at this (http://javascriptweblog.wordpress.com/2010/11/29/json-and-jsonp/)
var jsonp = {
callbackCounter: 0,
fetch: function(url, callback) {
var fn = 'JSONPCallback_' + this.callbackCounter++;
window[fn] = this.evalJSONP(callback);
url = url.replace('=JSONPCallback', '=' + fn);
var scriptTag = document.createElement('SCRIPT');
scriptTag.src = url;
document.getElementsByTagName('HEAD')[0].appendChild(scriptTag);
},
evalJSONP: function(callback) {
return function(data) {
var validJSON = false;
if (typeof data == "string") {
try {validJSON = JSON.parse(data);} catch (e) {
/*invalid JSON*/}
} else {
validJSON = JSON.parse(JSON.stringify(data));
window.console && console.warn(
'response data was not a JSON string');
}
if (validJSON) {
callback(validJSON);
} else {
throw("JSONP call returned invalid or empty JSON");
}
}
}
}

The response from http://translate.google.ru/translate_a/t?client=x&text=entertext&sl=en&tl=pl i JSON, not JSON-P. Accessing JSON-data this way is against the cross-site policies, as the browsers prevent such responses to be returned to the client.
As you are allowed to include scripts from other domains, JSON-P is a way of transfering data as javascript (not JSON). You need to find an API supporting JSON-P (I'm not sure if the Translate API supports JSON-P) or create a proxy on the same domain as your client application to access the JSON data.
Read more about the JSON-P protocol here: http://json-p.org/
To create a proxy, you'll need to implement a service that fetches the content of the Translate API and reprint it in the response.
Example:
/jsonProxy?text=foo
Should return the contents of http://translate.google.ru/translate_a/t?client=x&text=entertext&sl=en&tl=pl
...but you won't have to access it from another domain.

I think the MIME type of the response should be 'application/json'

Related

Google Calendar API Freebusy JQuery $.post gets 400 (Bad Request) Error

I am new to javascript, JQuery and Google API, so the answer to this question may be a very simple thing that I am overlooking. I've checked all available Google Calendar Freebusy Questions on this site, but I can't manage to make their answers fit my code in any way.
I am trying to write a script for an html page that checks a public calendar's freebusy query. Google says that the HTTP Request should be
POST https://www.googleapis.com/calendar/v3/freeBusy
with a request body of
{
"timeMin": datetime,
"timeMax": datetime,
"timeZone": string,
"groupExpansionMax": integer,
"calendarExpansionMax": integer,
"items": [
{
"id": string
}
]
}
My current html page includes the latest jquery library, and the script I'm writing. Calling the script on the page results in a Failed to load resource: the server responded with a status of 400 (Bad Request) error. A further dig into the error information returns a parse error with "This API does not support parsing form-encoded input."
My script looks like this:
(function ($) {
$.GoogleCalendarFreebusy = function (options) {
var defaults = {
apiKey: '[projectkey]',
getID: '[id]#group.calendar.google.com',
element: '#div'
};
options = $.extend(defaults, options);
$.post('https://www.googleapis.com/calendar/v3/freeBusy?key=' + options.apiKey,
{"items":[{"id": getID }],"timeMin":"2015-04-10T14:15:00.000Z","timeMax":"2015-04-20T23:30:00.000Z"}, "null", "json")
.done(function(data) {
loaded(data);
});
function loaded(data) {
var status = data.calendars[getID].busy;
console.log(status);
if(status.length !== 0 ) {
for(var i = 0; i < status.length; i++) {
var statusEntry = status[i];
var startTime = statusEntry.start;
var endTime = statusEntry.end;
}
var now = new Date().toISOString();
var element = options.element ;
var name = element.substr(1);
if (now > startTime && now < endTime){
$(options.element).append( 'Available!');
}
else {
$(options.element).append( 'Unavailable!');
}
} else {
$(options.element).append('Unavailable!');
}
}
};
})(jQuery);
My request is receiving the proper response in the Google Explorer "Try It", so I think it may be javascript error/json request I'm overlooking? Thanks in advance for your help and advice.
Google Calendar API Post requests need to have the content-type specified as JSON to avoid the above error. Processing the POST as an AJAX request with contentType specified solves this error.
$.ajax({
url: 'https://www.googleapis.com/calendar/v3/freeBusy?key=' + options.apiKey,
type: 'POST',
data: '{"items":[{"id": "[id]#group.calendar.google.com"}], "timeMin": "2015-04-10T14:15:00.000Z", "timeMax": "2015-04-20T23:30:00.000Z"}',
contentType: 'application/json; charset=utf-8',
dataType: 'json',
success: 'null'
})
Thank you for the suggestions!

how return data since a GET request with node.js

I have a little trouble with an Node application, the problem is: I have an Script in a web site "x" and this script calls a function that is on another server (like analytics), I'm calling the function with ajax and when the function returns the data, happen some curious, when I check the network with Developer Tools in Chrome, the callback shows the response like I wanted in JSON format, but not show me data. My code:
var xml2js = require('xml2js'),
http = require('http'),
request = require('request');
var parserController = function (aw){
console.log('Parse Controller load');
aw.get('/ads/:keyword/:sid/:pid/:count', function (req,res){
res.setHeader('Content-Type', 'application/json');
request('http://'+req.params.sid+'.'+req.params.pid+'.autoweb-xml.com/feed?&sid='+req.params.sid+'&auth=2Al5&subid=&q='+req.params.keyword+'&ip=127.0.0.1&ua=Mozilla/5.0%20(Windows%20NT%206.1;%20WOW64;%20rv:26.0)%20Gecko/20100101%20Firefox/26.0&ref=awebads.lan&count='+req.params.count+'&state=&city=', function (error, response, body) {
if (!error && response.statusCode == 200) {
var parser = xml2js.parseString;
var data = '';
parser(body,{explicitRoot : false}, function (err, result){
if(!err){
data = result;
dataP=data.results[0];
dataS=dataP.sponsored[0];
console.log(dataS.listing);
return res.send(dataS.listing);
}
else
{
console.log(err);
}
})
}
})//en del request
});
};
and my call function is:
var xhr = $.ajax({
type:'GET',
url:'http://HOST/ads/'+configParams.keyword+'/'+configParams.envSource+'/'+configParams.envPublisher+'/'+configParams.envCount,
dataType : 'jsonp',
async: false,
crossDomain : true
})
xhr.done(function (data){
console.log(data);
data.forEach(function(item){
window.collections.ads.add(item);
});
}).fail(function (err) {
//console.log('failed');
//console.log(err)
});
when I display the data in the console, this part show me the XMLHTTPRequest, thanks in advance for your help
You are sending JSON:
the callback shows the response like I wanted in JSON format
… but the client is expecting JSON-P
dataType : 'jsonp',
Either:
Tell the client to expect JSON (or just remove the dataType line and let it use the Content-Type header) and set Access-Control-Origin on the response headers to give the site permission to access it cross-domain or
Send JSON-P back instead (look at callback in the query string, send Content-Type: application/javascript (not JSON!), and return callback_value(your_json); as the response body.
In case of jsonp you need a callback function and then return your response in that callback.

How do I get Mercury Editor to redirect to a new resource?

After watching RailsCast #296 about Mercury Editor, I am trying to get the editor to redirect to a newly created resource.
I can already redirect on the client-side using JS and window.location.href=. But for a new resource, I cannot "guess" its URL on the client-side. I need it to be in the server response.
However, the problem is that I don't see the possibility of using the server response in the editor. No matter what the controller renders, the server response is discarded by Mercury instead of used as an argument to my function for mercury:saved.
Is there a way to get around this?
I was able to do this on update by sending a valid JSON string back. I would assume create works the same way. check firebug to make sure you're not getting an error in the jQuery.ajax call that Mercury uses.
posts_controller.rb
def mercury_update
post = Post.find(params[:id])
post.title = params[:content][:post_title][:value]
post.body = params[:content][:post_body][:value]
post.save!
render text: '{"url":"'+ post_path(post.slug) +'"}'
end
mercury.js:
jQuery(window).on('mercury:ready', function() {
Mercury.on('saved', function() {
window.location.href = arguments[1].url
});
});
note: I'm using friendly_id to slug my posts
Redirecting on the server side doesn't work because the save button is just an jQuery.ajax call:
// page_editor.js
PageEditor.prototype.save = function(callback) {
var data, method, options, url, _ref, _ref1,
_this = this;
url = (_ref = (_ref1 = this.saveUrl) != null ? _ref1 : Mercury.saveUrl) != null ? _ref : this.iframeSrc();
data = this.serialize();
data = {
content: data
};
if (this.options.saveMethod === 'POST') {
method = 'POST';
} else {
method = 'PUT';
data['_method'] = method;
}
Mercury.log('saving', data);
options = {
headers: Mercury.ajaxHeaders(),
type: method,
dataType: this.options.saveDataType,
data: data,
success: function(response) {
Mercury.changes = false;
Mercury.trigger('saved', response);
if (typeof callback === 'function') {
return callback();
}
},
error: function(response) {
Mercury.trigger('save_failed', response);
return Mercury.notify('Mercury was unable to save to the url: %s', url);
}
};
if (this.options.saveStyle !== 'form') {
options['data'] = jQuery.toJSON(data);
options['contentType'] = 'application/json';
}
return jQuery.ajax(url, options);
};
So your redirect is sent to the success callback, but the page doesn't actually re-render, as with any successful AJAX request. The author discusses overriding this very function here. It also looks like there might be some room to maneuver here by passing a callback function to save.
Btw, another way to do what #corneliusk suggests is:
render { json: {url: post_path(post.slug)} }
Either way, the response body is passed as an argument to the function in the mercury:saved callback.

How to override Backbone.sync so it adds the apikey and username at the end?

I am using backbone-tastypie, but I am having the toughest time getting it to work properly. In Tastypie, I am using ApiKeyAuthentication for my resources, so every ajax request, I need to append the apikey and username to the end of a request or send additional headers that add on the username and api key.
I am trying to remove a view and its model using backbone with the following code:
// Remove the goal update view from the DOM
removeItem: function() {
this.model.destroy({wait: true, success: function() {
console.log("success");
}, error: function() {
console.log("error");
}});
},
After the function executes, the browser tries to do a GET request on the following URL:
:8000/api/v1/update/2/
It does not include the api_key or username at the end, and it has a trailing slash at the end of the url. I think it is trying to use Backbone.oldSync to do the GET request. How would I make it so the sync does include the username/api key at the end and removes the trailing slash?
In all of the other requests, I have made it so the api key and username is appended to the end of the http request by adding the following code to backbone-tastypie:
if ( !resp && ( xhr.status === 201 || xhr.status === 202 || xhr.status === 204 ) ) { // 201 CREATED, 202 ACCEPTED or 204 NO CONTENT; response null or empty.
var location = xhr.getResponseHeader( 'Location' ) || model.id;
return $.ajax( {
url: location + "?" + "username=" + window.app.settings.credentials.username + "&api_key=" + window.app.settings.credentials.api_key,
success: dfd.resolve,
error: dfd.reject,
});
}
Let's explore the possibilities
Using headers
Backbone.sync still just uses jQuery ajax so you can override ajaxSend and use headers to send information along.
$(document).ajaxSend(function(e, xhr, options)
{
xhr.setRequestHeader("username", window.app.settings.credentials.username);
xhr.setRequestHeader("api_key", window.app.settings.credentials.api_key);
});
Using Ajax Options
If you need to send the information in just one or two locations, remember that the destroy, fetch, update and save methods are just shortcuts to the ajax caller. So you can add all jQuery ajax parameters to these methods as such:
// Remove the goal update view from the DOM
removeItem: function ()
{
this.model.destroy({
wait: true,
success: function ()
{
console.log("success");
},
error: function ()
{
console.log("error");
},
data:
{
username: window.app.settings.credentials.username,
api_key: window.app.settings.credentials.api_key
}
});
}
Overriding jQuery's ajax method
Depending on your needs, this might be the better implementation (note that this is no production code, you may need to modify this to fit your needs and test this before using it)
(function ($) {
var _ajax = $.ajax;
$.extend(
{
ajax: function (options)
{
var data = options.data || {};
data = _.defaults(data, {
username: window.app.settings.credentials.username,
api_key: window.app.settings.credentials.api_key
});
options.data = data;
return _ajax.call(this, options);
}
});
})(jQuery);
Just for future readers of this post, when you do a model.destroy() you can't pass any data because the delete request doesn't have a body, see this issue for more info:
https://github.com/documentcloud/backbone/issues/789

WCF javascript call cross domain

I am new to javascript and I have a problem that is giving me hard times.
I want to put in a page a tracking javascript. This script will call a wcf service to track client browser information, page visited and timestamp. The problem is that I get: "405 Method Not Allowed" error on javascript call. The service will be on another domain. Now I test this on localhost. The service is working fine because I can call it from a new page in browser. Did you experienced the same problem? How can I fix this?
My javascript code is:
Wcf service code:
[ServiceContract(Name = "CustomersAssistantService", Namespace = "CustomersAssistantService")]
public interface ICustomersAssistantService
{
[OperationContract]
[WebGet]
string DoWork();
[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Wrapped, ResponseFormat = WebMessageFormat.Json)]
[OperationContract]
string Sum(int n1, int n2);
}
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class CustomersAssistantService : ICustomersAssistantService
{
public string DoWork()
{
return "work done";
}
public string Sum(int n1, int n2)
{
return (n1 + n2).ToString();
}
}
Javascript call:
function CallWcf1(){
var _I = this;
var url = "http://localhost:58399/CustomersAssistantService.svc/customersAssistantService/";
var methodUrl = _I.serviceUrl + 'dowork';
$.ajax( {
url: methodUrl,
data: '',
type: "GET",
processData: false,
contentType: "application/json",
timeout: 10000,
dataType: "text", // not "json" we'll parse
success:
function(res)
{
if (!callback) return;
// *** Use json library so we can fix up MS AJAX dates
var result = JSON2.parse(res);
// *** Bare message IS result
if (bare)
{ callback(result); return; }
// *** Wrapped message contains top level object node
// *** strip it off
for(var property in result)
{
callback( result[property] );
break;
}
},
error:
function(xhr)
{
if (!error) return;
if (xhr.responseText)
{
var err = JSON2.parse(xhr.responseText);
if (err)
error(err);
else
error( { Message: "Unknown server error." })
}
return;
}
});
}
Am I doing something wrong?
Thanks a lot, Radu D
You're running into the Same Origin Policy. Ajax requests are limited to talking to the same origin; cross-domain requests will typically be denied.
Depending on your needs, there are various approaches:
If your users will be using only quite modern browsers (so, not IE7), you could implement Cross Origin Resource Sharing on your server. This is a standard from the W3C that allows a server to open up access to its resources cross-origin, but it's only supported in modern browsers. (And on IE, it's supported, but not via the usual XMLHttpRequest object; instead, you have to use the XDomainRequest object.)
You could implement a JSON-P interface.
If all you want to do is send a notification to the other domain, you can just load a resource from it (an img, a script, whatever) by adding those elements with the relevant src attribute; this means, though, that you're limited to using the GET method which is supposed to be for idempotent resources.
As far as I know, request for WCF must use the POST method, so change to:
type: "POST",
In the AJAX call.

Categories

Resources