Prediction request end up with "invalid data" errors - google-api-nodejs-client

I get errors when posting prediction requests, but when posting the same requests from the online interface (from Google's API reference page) works well.
I have also posted a new issue on the Git repository, but it seems that no-one even looks at these issues. How lame of Google !!
Well I am posting predict request, which look like this:
var parameters = {
auth: jwtClient,
project: googleProjectID,
id: 'interest_classifier',
input: {
csvInstance: ["country united states", "/location/location"]
}
};
return prediction.trainedmodels.predict(parameters, function(err, response) {
if (err) {
logger.info(null, "prediction err ", err);
}
logger.info(null, "response from predict ", response);
return callback(null, response);
});
And I get this:
err { [Error: Input data invalid.]
code: 400,
errors:
[ { domain: 'global',
reason: 'invalidValue',
message: 'Input data invalid.' } ] }
To clarify: my trained model contains a value and two textual features.
Again, when running this from the online tool (client side) it works well, only when I run it from my node.js server, does it fail.
What's up with that? Anyone knows?
Could this be some encoding issue? request headers?
EDIT:
this is how i authenticate :
var jwtClient = new google.auth.JWT('*****#developer.gserviceaccount.com', 'keys/key.pem', null, ['https://www.googleapis.com/auth/prediction']);
jwtClient.authorize(function(err, tokens) {
logger.info(null, "authorizing");
if (err) {
logger.info(null, "error ", err);
} else {
return logger.info(null, "authenticated ", tokens);
}
});

OK,
So I've dug into Google's code and found out an important detail that is not properly documented.
I think this might be relevant to other people using this library, not only the ones who use google predict.
So most requests need to include a project id in the parameters, but in some cases you also need to include post data (like in my case).
I was trying to include this post data directly in the parameters like so :
var parameters = {
auth: jwtClient,
project: googleProjectID,
id: 'interest_classifier',
input: {
csvInstance: ["country united states", "/location/location"]
}
};
Now I found (this is not documented !!) that the whole part which belongs to the post data should be included within a "resource" field, like this:
var parameters = {
auth: jwtClient,
project: googleProjectID,
id: 'interest_classifier',
resource:{
input: {
csvInstance: ["country united states", "/location/location"]
}
}
};
I believe this will be relevant to any request which includes post data.
Cheers,
Ilan

Related

Zapier POST with error "body used already for"

Basically following the code example verbatim, but trying to make a POST request with fetch
fetch('YOUR URL HERE', { method: 'POST', 'body': content })
.then(function (res) {
console.log(res.text());
return res.text();
})
.then(function (plain) {
var output = { okay: true, raw: plain };
callback(null, output);
})
.catch(callback);
Results in angry red box with:
We had trouble sending your test through. Please try again. Error:
Error: body used already for: https://YOURURLHERE
Not sure what it means?
...and then I realized it's not a Zapier question, but a fetch issue.
Google says it's because of what I'm doing in the promise, by trying to read the res stream as text twice (note the two res.text() calls).
(for about 2 minutes I had omitted what I thought was an unimportant detail from the question, the console.log line which was the culprit)

Can't retrieve the play store reviews for my app

I am trying to get the reviews for my app from the playstore using the new reviews api from the android publisher service.
The app key is me.jadi (https://play.google.com/store/apps/details?id=me.jadi) as you can see it have reviews posted for it.
Here is the code I'm using:
var google = require('googleapis');
var secrets = require('./secrets.json');
var androidpublisher = google.androidpublisher('v2');
var authClient = new google.auth.JWT(
secrets.client_email, null, secrets.private_key,
['https://www.googleapis.com/auth/androidpublisher'], null);
authClient.authorize(function (err, tokens) {
if (err) {
return console.log(err);
}
androidpublisher.reviews.list({ auth: authClient, packageName: 'me.jadi' }, function (err, resp) {
if (err) {
return console.log(err);
}
});
});
It doesn't contain any errors for the auth nor for the actual service request. But the result is always an empty object.
So I'm trying to identify the problem,
is there something wrong with the code
do I need to opt-in specifically somewhere to use the API
does the API have any limitations, like geographic (the service is allowed only for the US devs)
or maybe the service have some bugs because it is still in beta
I found the answer my self, and I'll post it here for future reference.
The problem with my specific case was that I didn't have reviews posted or modified in the last week.
And the API documentation clearly states that it will keep history of the reviews in the last seven days.
Once I get a new review I tried the code and the review was successfully retrieved.

Configuring Restivus POST method for Meteor

I have the following Restivus configuration:
if(Meteor.isServer){
Restivus.configure({
});
//Allow Restivus to manage Reports
Restivus.addCollection('reports');
Restivus.addRoute('newReport/:message', {}, {
// POST
post: {
action: function(){
var response = null;
var message = this.urlParams.message;
if(message){
console.log("Message received: " + message);
return {status: "success", data: message};
} else {
console.log("Message empty...");
return {status: "fail", message: "Post not found"};
}
//Response to caller
return;
}
}
})
}
Following the explanation of Restivus, when I make a GET call to http://localhost:3000/api/newReport/ I should get a "Get All" result from the server, on the caller.
However, if I use curl -X GET http://localhost:3000/api/newReport/ on the command line, I seem to be getting the HTML code of the site at api/NewReport/ (which is empty, except for the header and empty body)
Knowing that, I know my error is in the Restivus Route configuration, but I cannot pinpoint the reason.
The expected behavior is that when I make a POST from a Ruby script, I should get a returned message (Ok or Fail), and in my Meteor console, I should see either "Message received" or "Post not found" (both placeholders).
Additional question, is there a way to disable the default GET method Restivus creates when we add a collection?
You have to create a variable in the JavaScript part and use that in the Restivus.addCollection() call.
Reports = Mongo.Collection('reports')
if(Meteor.isServer){
Restivus.configure({
});
//Allow Restivus to manage Reports
Restivus.addCollection(Reports);
...

Apigee push notification - one

Apigee's push notification is documented here.
http://apigee.com/docs/api-baas/content/introducing-push-notifications
I tried this with the js sdk that Apigee provides here http://apigee.com/docs/app-services/content/installing-apigee-sdk-javascript. It looks like only the client can generate a notification to itself?
But I have a scenario where I would like to push notifications to multiple clients from a nodejs job that runs once every hour. Something like this, but from the nodejs sdk not from the js sdk.
var devicePath = "devices;ql=*/notifications";
How do I do this?
As remus points out above, you can do this with the usergrid module (https://www.npmjs.com/package/usergrid).
You are basically trying to construct an API call that looks like this (sending a message by referencing a device):
https://api.usergrid.com/myorg/myapp/devices/deviceUUID/notifications?access_token= access_token_goes_here '{"payloads":{"androidDev":"Hello World!!"}}'
Or like this (sending a message by referencing a user who is connected to a device)
https://api.usergrid.com/myorg/myapp/users/fred/notifications?access_token=access_token_goes_here '{"payloads":{"androidDev":"Hello World!!"}}'
You can do this with code that looks something like this:
var options = {
method:'POST',
endpoint:'devices/deviceUUID/notifications',
body:{ 'payloads':{'androidDev':'Hello World!!'} }
};
client.request(options, function (err, data) {
if (err) {
//error - POST failed
} else {
//data will contain raw results from API call
//success - POST worked
}
});
or
var options = {
method:'POST',
endpoint:'users/fred/notifications',
body:{ 'payloads':{'androidDev':'Hello World!!'} }
};
client.request(options, function (err, data) {
if (err) {
//error - POST failed
} else {
//data will contain raw results from API call
//success - POST worked
}
});
Note: the second call, that posts to the users/username/notifications endpoint assumes that you have already made a connection between the user and their device (e.g. POST /users/fred/devices/deviceUUID).

Baasbox and Javascript

I'm trying BaaSbox, a free Backend as a Service. But it has no out-of-the-box Javascript support I can use right away (yet, only iOS and Android)
I'm having trouble sending the right curl command from javascript, anyone happen to know a good resource or a simple working $.ajax template? I've tried a few examples from stackoverflow, but none of them specifically aimed at BaaSbox.
I've tried following the Java instructions on their site here. Just making a simple login work, but I keep getting the wrong responses from the server.
Or on the other hand, anyone know a good, free alternative to BaaSbox? I just want to be able to install it on my own server, no paid plans or whatever.
in the download page there is a preliminary version of the JS SDK (added few days ago).
The documentation is on the way, however in the zip file you can find a simple example.
For example to perform a signup:
//set the BaasBox parameters: these operations initialize the SDK
BaasBox.setEndPoint("http://localhost:9000"); //this is the address of your BaasBox instance
BaasBox.appcode = "1234567890"; //this is your instance AppCode
//register a new user
BaasBox.createUser("user", "pass", function (res, error) {
if (res) console.log("res is ", res);
else console.log("err is ", error);
});
Now you can login into BaasBox
//perform a login
$("#login").click(function() {
BaasBox.login("user", "pass", function (res, error) {
if (res) {
console.log("res is ", res);
//login ok, do something here.....
} else {
console.log("err is ", error);
//login ko, do something else here....
}
});
Once the user is logged in he can load the Documents belonging to a Collection (the SDK automatically manages the Session Token for you):
BaasBox.loadCollection("catalogue", function (res, error) { //catalogue is the name of the Collection
if (res) {
$.each (res, function (i, item) {
console.log("item " + item.id); //.id is a field of the Document
});
} else {
console.log("error: " + error);
}
});
However under the hood the SDK uses JQuery. So you can inspect it to know how to user $.ajax to call BaasBox.
For example the creatUser() method (signup) is:
createUser: function (user, pass, cb) {
var url = BaasBox.endPoint + '/user'
var req = $.ajax({
url: url,
method: 'POST',
contentType: 'application/json',
data: JSON.stringify({
username: user,
password: pass
}),
success: function (res) {
var roles = [];
$(res.data.user.roles).each(function(idx,r){
roles.push(r.name);
})
setCurrentUser({"username" : res.data.user.name,
"token" : res.data['X-BB-SESSION'],
"roles": roles});
var u = getCurrentUser()
cb(u,null);
},
error: function (e) {
cb(null,JSON.parse(e.responseText))
}
});
}