Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Google Javascript API (gapi) - problems with .load

I am trying to use the Google plus API (via googie-api-javascript) implementation like so (omitting full code):

var clientId = '7454475891XxxxxxXom4c6n.apps.googleusercontent.com'; //fake client
var apiKey = '-uTH_p6NokbrXXXXXXXXXXXXX'; //Fake Key
var scopes = 'https://www.googleapis.com/auth/plus.me';

function handleClientLoad() {
   gapi.client.setApiKey(apiKey);
   window.setTimeout(checkAuth,1);
}

function checkAuth() {
   gapi.auth.authorize({client_id: clientId, scope: scopes, immediate: true}, handleAuthResult);
}


function handleAuthResult(authResult) {        
  if (authResult && !authResult.error) {          
    makeApiCall();
  } else {
    //handle user-approval
  }
}

  // Load the API and make an API call.  Display the results on the screen.
function makeApiCall() {
    gapi.client.load('plus', 'v1', function() {
      var o = gapi.client.plus;
      alert(o);
    });
}

The code works well upto the point of gapi.client.load (including the user allowing access) - this callback gets called but alert(o) will return undefined.

Upon inspecting the HTTP request I see the .load issues a request to:

https://content.googleapis.com/discovery/v1/apis/plus/v1/rpc?fields=methods%2F*%2Fid&pp=0&key=-uTH_p6NokbrXXXXXXXX

This returns HTTP 400 with the following message:

{"error":{"errors":[{"domain":"usageLimits","reason":"keyInvalid","message":"Bad Request"}],"code":400,"message":"Bad Request"}}

My question is - what do I need to change to make this work? Is there some secret setting I need to enable ? Google+ is enabled in the google-developer-console under the APIs list.

Thanks for the help, Alon

like image 482
Alon Avatar asked Dec 26 '13 13:12

Alon


2 Answers

Problem: .load issues a request to the google discovery service to load the .JS. The service will error out if the request it receives contains an api-key. (I don't know why the library works like this, it seems like a bug?)

Fix:

gapi.client.setApiKey(""); //NEW
gapi.client.load('plus', 'v1', function()
//re-add the key later if you need it

From Discovery Service docs: requests you make to the Discovery Service API should not include an API key. If you do provide a key, the requests will fail.

Weird... :P

like image 124
Alon Avatar answered Oct 08 '22 12:10

Alon


A little update & more of an explanation. The current Discovery Service page is a little more specific now. They indicate that if the app has an Oauth2 token, then the API Key value is not required. However, I also found that if I have an authenticated user and thus an Oauth2 token (access_token) present, the Discovery Service fails with the error noted in the OP. This seems to contradict the documentation.

You can see the token in the developer tools console with:

console.log(gapi.auth2.getAuthInstance().currentUser.get().getAuthResponse());

Embed that somewhere in a <script>...</script>in your HTML or in a .js file that is called otherwise. Must be after gapi.load(...). It'll stop the script if executed before gapi.load(...) is called.

To get a current user this has to be after the user is authenticated, of course. It does return an object if a user has not been authenticated however. If you are in Chrome, you can expand The Object in the developer tools console window to get a nice outline format of all the stuff in the auth response.

Note that currentUser is undefined prior to a successful authentication. Since this 'fails silently' you should use a conditional statement to verify either the sign in status or that a current user exists in your real code.

For completeness the object instantiation process in my app goes like this, at a high level:

1.) gapi.load(...) - After this gapi.client, gapi.auth2 and other objects are available.

2.) gapi.client.setApiKey("") would be called to 'clear' the api key if it had been set previously for some other purpose.

3.) gapi.auth2.init(...) - After this the auth instance is available via gapi.auth2.getAuthInstance .

4.) Then the login is kicked off using the .signIn() method of the auth instance. The auth instance would be instantiated with something like auth_instance = gapi.auth2.getAuthInstance(); If that's how you do it then the sign in would be auth_instance.signIn().

(...) - means there are several parameters needed.

I also found the Google tictactoe example useful as an example and a simple base for further work.

I hope this is helpful to someone!

like image 39
JackW327 Avatar answered Oct 08 '22 12:10

JackW327