Arxius

Archive for Octubre de 2015

Working with google APIs

We’ve already seen how to develop a whole web app using the «Web App Scripts». However, many times we would like to keep our web app into another place/server, so in this case we must use the google APIs to interact with the google services. Let’s see how to do it.

Grant access to the APIs

Before coding anything, we must grant the access to the APIs we’re going to use into our google account.

So go to : https://console.developers.google.com/ and create a new project (for instance, project2):

gapi

Then, go to «APIs & auth», «APIs» option of the new Project, and there select the API you want to enable for the project. In our example it will be the «Drive API» :

gapi

And set “enable” the API for the project :

gapi

You may add more information about why your app needs to be connected into the Google Drive Service :gapi

Now go to the «APIs & auth», «Credentials» option, and add a new credential of «OAuth 2.0 client ID» :

gapi

There are 2 authentication methods depending on which sort of use it will be needed:

  1. We could launch requests to APIs which doesn’t need to access private data in the google account, and therefore it doesn’t need authorization, so we can use a simple access with gapi.client.setApiKey(API KEY);
  2. If we have to access private data with the APIs, we have to use the OAuth 2.0.

In the example, we’ll use the OAuth 2.0 method, so we’ll work with private data.

However, before creating it, you must setup the «Consent Screen». This is the screen that will be shown to get the authorization when the app tries to access google API for first time. So go to set it up :

gapi

type a «Product Name» and save it.

gapi

Afterwards, choose the «Web application» type and – for more safety – I advise to filter the origin domains where the app will access (in the example, we’ll use a local server, so we’ll access from local http://localhost) :

gapi

Then, you will get the «Client ID» and «Client Secret» keys. Keep your «Client ID», because we’ll need it later.

gapi

So we’ve already got it. Now we can access the services using the API.

The first time you try to access to the API, if the request parameter «immediate» is false (we’ll see it later), a window screen pop up will ask you for login into google account (if you’re not yet):

gapi

and also to allow the access to the google service:

gapi

Access the API

Now that we have the access available, let’s going to see how to use it.
We’ve built this simple html page to show an easy example :

<!DOCTYPE html>

<html>

<head>

https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js

https://apis.google.com/js/client.js

var clientId = ’10…………….apps.googleusercontent.com’;

var scopes = ‘https://www.googleapis.com/auth/drive.metadata.readonly&#8217;;

function checkAuth() {

$(‘body’).append(‘

The authorization request has been launched

‘);

gapi.auth.authorize({

‘client_id’: clientId,

‘scope’ : scopes,

‘immediate’: true

},

handleAuthResult);

}

function handleAuthResult(authResult) {

if (authResult && !authResult.error) {

$(‘body’).append(‘

The authorization request has been succesful

‘);

$(‘.send_request’).removeAttr(‘disabled’);

} else {

$(‘body’).append(‘

There was an ERROR!

‘);

}

}

</head>

<body style=”width: 100%; height: 100%; overflow: hidden;”>

<h1> Google API access example </h1>

<button id=”authorize-button1″ onclick=”checkAuth();”> check Authorization </button>

<button class=”send_request” onclick=”method_1_request();” disabled=”true”> Request method 1 (request) </button>

<button class=”send_request” onclick=”method_2_request();” disabled=”true”> Request method 2 (load) </button>

<button class=”send_request” onclick=”method_3_request();” > Request method 3 (CORS) </button>

</body>

</html>

The first we need is include the google API’s JS library into our page (https://apis.google.com/js/client.js). We’re going to launch the request with a javascript code, although there’re many other ways to do it. You can also use PHP, Java, Python, etc.. (https://developers.google.com/api-client-library/).

As you can guess, before anything the app has to authenticate the client access to the API services. In the example, as we’ve set it up before, we’ll use the OAuth 2.0. As you can see in the code, we put a button that calls a javascript function «checkAuth», where we use the gapi.auth.authorize() function. This uses 2 parameters. The first parameter is an object with the following values:

  1. client_id: This is the ID you’ve got after setting up the google API service access. Just put the code there, or use an input parameter to set it.
  2. scope: Here we have to specify which scope (part of the service) we will use. Each API has many scopes, and depending on what our app wants to do, we must choose the most suitable. In the example, we’re using the «drive.metadata.readonly» scope of the Google Drive API. However we could use many others.
  3. immediate: This (true/false) value – as we’ve seen before – sets the app to show the authorization popup window, or not. (true = it doesn’t show the popup / false = it does show the popup).

And the second parameter, is a handler function (handleAuthResult), to be called after the request finishes, in order to handle the answer. The most common we should do here is to test the result of the request with the parameter (authRestful), and then proceed as the app needs.

If you try to execute the example, you’ll see that there’s an authorization request to the API:

gapi

gapi

As you may know, the google API works as a RESTful method. It means that the client (javascript, or any else we’re using) and the server (google) uses a http URL structured interface to compose the messages for sending requests and responses. You can learn more about this process there.

So, let’s see how to build and send a request. Here we have 3 different options. We can either use a simple request call (with gapi.client.request), or a faster technique, that loads previously the API interface. Even more, we also could build manualy an XHR request (with CORS).

Method 1: gapi.client.request

The easier one. We can quickly compose a http request using the gapi.client.request function. This uses an object parameter where we must set the required values to build the request, as the «path» (in the example, we’re using the drive file list request), the «method» (GET by default for reading, although it could be POST / PUT / DELETE), «params» for specific parameters of the request, and «headers» and «body», which we’re not going to use for now.

function method_1_request() {
    $(‘body’).append(‘<p>Drive API direct request has been launched</p>’);
    var restRequest = gapi.client.request({
       ‘path’ : ‘https://www.googleapis.com/drive/v2/files&#8217;,
        ‘method’ : ‘GET’,
        ‘params’ : { ‘maxResults’: 10, ‘q’ : ‘trashed=false’ }
        });
    restRequest.then(
       function(resp) { load_result(resp.result); }, // Success function
       function(reason) { $(‘body’).append(‘<p>There was an ERROR!</p>’); }); // Error function
}

After the request, as we have previously set with the «restRequest.then», it will launches the response handled function (load_result if it goes ok).

The request we’ve used for the example (drive/v2/files), as you may have already read in the documentation, asks google Drive for a metadata list of our stored files, and returns it in a JSON structure:

{
“kind” : “drive#fileList”,
“etag” : etag,
“selfLink” : string,
“nextPageToken” : string,
“nextLink” : string,
“items” : [ files Resource ]
}

As an example, we could print it into the page with and easy dynamic script :

function load_result(resp) {
    $(‘body’).append(‘<p>Drive API direct request has been successful</p>’);
    var files = resp.items;
    if (files && files.length > 0) {
        $(‘body’).append(‘<ul>’);
        for (var i = 0; i < files.length; i++) {
           $(‘body’).append(‘<li>’ + files[i].title + ‘ – ‘ + files[i].id + ‘</li>’);
        }
        $(‘body’).append(‘</ul>’);
    } else {
        $(‘body’).append(‘<p>No files found.</p>’);
    }
}

And get the following result :

gapi

As you’ve seen, after pushing the button, the page launched a XHR request to talk with the API, with the URL and defined parameters:

gapi

Method 2: gapi.client.load

There’s another way to do exactly the same, though with a better performance. We could load the full client API’s interface, with the gapi.client.load() function, and henceforth use it to launch many requests. As you can imagine, it should be faster in a many requests scenario.

After loading the API interface, we can call all its available requests (for instance, those of the Drive API) through each of its functions (like gapi.client.drive.files.list). So we can manage to the same result as in the last method with the following code:

function method_2_request() {
    gapi.client.load(‘drive’, ‘v2’,
function() {
$(‘body’).append(‘<p>Drive API interface loaded</p>’);
var request = gapi.client.drive.files.list({ ‘maxResults’: 10, ‘q’ : ‘trashed=false’ });
request.execute(load_result);
}
);
}

As you can see, the result is the same, and the XHR request has the same structure and parameters :

gapi

Method 3: Direct request with CORS

We have also another method to send a request to a google API: with a direct CORS request.

To take it lighter, we may just load the auth.js library instead of the whole client.js :

https://apis.google.com/js/auth.js <!– use this for only CORS auth –>
https://apis.google.com/js/client.js <!– use this for full client API –>

and then, after getting permission from the gapi.auth.authorize function, built the XHR request directly:

function method_3_request() {
$(‘body’).append(‘<p>Launching a manual request with CORS</p>’);
gapi.auth.authorize({
client_id : clientId,
scope : scopes,
immediate : true},
function() {
var oauthToken = gapi.auth.getToken();
var xhr = new XMLHttpRequest();
var url_request = ‘https://www.googleapis.com/drive/v2/files?maxResults=10‘; // + ‘&access_token=’ + encodeURIComponent(oauthToken.access_token);
$(‘body’).append(‘<p>xhr: ‘ + url_request + ‘</p>’);
xhr.open(‘GET’, url_request);
xhr.setRequestHeader(‘Authorization’, ‘Bearer ‘ + oauthToken.access_token);
xhr.onload = function() {
var obj_res = JSON.parse(xhr.responseText);
load_result(obj_res);
};
xhr.send();
});
}

This is the same way as if we would have buit a simple XMLHttpRequest.

Nevertheless, we shouldn’t forget adding the authorization token to the request. We have 2 ways to do it:

  1. Add the access_token parameter to the URL:
    var oauthToken = gapi.auth.getToken();
    var url_request = ‘https://www.googleapis.com/drive/v2/files?maxResults=10‘ + ‘&access_token=’ + encodeURIComponent(oauthToken.access_token);
  2. Or add it to the request’s header (with the setRequestHeader function):
    var oauthToken = gapi.auth.getToken();
    xhr.setRequestHeader(‘Authorization’, ‘Bearer ‘ + oauthToken.access_token);

There’s more info about this method right here.

Anuncis
Categories:Uncategorized

How to use Google App Scripts

Google has a huge collection of tools which allow developers interact with its services.

gapi1

One of my favourites is the Google App Scripts. This a great tool that allow us to develop software that can work together with the most Google common services, as Gmail, Calendar, Drive, Maps, Translator, etc. Actually, this is very similar to an API, but in my opinion, what Google people are offering here is something more powerful, and easier to use, than the Google APIs.

However, we can always use the Google APIs with the same aim, but for non complex aplications I think it is better to use “Google App Scripts”.

gapi2

To work with “Google App Scripts” we need a Google account. So all the references to the Google Services we are going to use, are going to point to the ones of the logged session in the browser.

“Google App Script” can be used in several ways. We are not going to talk about scripts integrated into the Google services. Rather we are going to suppose that we have a personal Web App, and we want to link it to one of our Google services.

At this point, we have 2 choices:

  • We can create our Web App completely as a “Google App Script”.
  • Or we can create a Script, and use it as an API, requested from another Web App.

We’re going to start with the first case.

Create a Web App Script

Beyond the “App Scripts”, we can also write an host a whole html dynamic page. The only thing we need to start, is a google account with a Google Drive service. The project will be stored as a file into your Google Drive unit. So you can create one directly with the Drive New File button:

gapi1

or going directly to this URL: https://script.google.com

Both cases, we’ll get the start wizard, where there are many options, but what we are looking for is the last of the left column «Web App»

gapi1

After choosing, we’ll get that framework with an implemented example :

Apps Script Framework

As you can see, the project has 4 files :

  1. Code.gs : Here we must write our Google App Scripts. With this functions we can bind our javascript code with Google Services.
  2. Index.html : This is the main html file of our web page.
  3. Javascript.html : Here we can write the javascript code for our web app.
  4. Stylesheet.html :  Here we can write the CSS styles for our web app.

Let’s try to execute the project:

  1. Go to the menu -> Publish -> Deploy as a web app
    gapi1
  2. Choose a name for the project (f.e. project_1).
    gapi1
  3. Select the Project options and access permissions.
    gapi1
  4. And then we’ll get an URL, ended with “/exec“, like this «https://script.google.com/macros/s/[…ID…]/exec».
    gapi1

This URL contains de ID of the Web App. You can change the last part of it in order to work with it. The possible endings are:

  • /exec     With this URL, you will send the request for the published version of the Web App, and get the HTML main page.
  • /dev       With this one, you will also send the request, but rather than the last published version, you’ll get the currently developed version of the Web App.
  • /edit      With this one, you will be redirected to the “web framework” where Google allows to develop the Web App.

If we try to go to the /exec url (in a new browser window), the first time we try to launch the app, Google will ask for grant for it. So give it permission.

gapi1

And finally we will get the result page. The example Web App shows a list with the name of our 20 first files in our Google Drive main folder.

gapi1

Let’s going to see how does it work.

Initial funcion doGet()

When we launch the a GET request URL (ended with /exec), the first what Google executes is the «doGet(e)» function, stored in the Code.gs file

gapi1

We can pass “GET parameters” to this function, collected in the “e” main parameter. For example, if I called the URL with “https://script.google.com/macros/s/%5B……%5D/exec?folderId=id001“, we could read (in the doGet function) the folderId value as e.parameter.folderId.

After recieving the GET request, it constructs a template object, taking the “Index.html” template file with the HtmlService.createTemplateFromFile() function.

If there’s a “folderId” parameter into the URL, it passes this value to the template variable, or ‘root’ value if not. It means that everywhere where there’s a <?=folderId?> in the template code, will be translated by the same value we’ve given to it.

And then, the template object launches 3 methods and returns the result.

  1. With the setSandboxMode(), the result web page is served into an iFrame structure, as a sandbox, in order to protect the client browser to execute malicious javascript code.
  2. With setTitle(), we can set a Window title.
  3. With evaluate(), the template code is evaluated, converted and returned as a final HTML code.

As you must have realized, this doGet() function only return an HTML code for our main page. We could write a simpler function like that :

function doGet(e) {
return HtmlService.createHtmlOutput(‘<html> <body> <p> Hello World </p> </body> </html’);
}

and after the URL request we would get this simple html page.

Template file Index.html

Now, let’s take a glance to the Index.html template file :

gapi1

As you can see, there are some <?=folderId?> template tabs, which as we know they will be overwritten with the URL parameter value.

However, there are also another <?!= HtmlService.createHtmlOutputFromFile(‘[file name]’).getContent(); ?> template tabs.

When the template is evaluated, the createHtmlOutputFromFile(”) function creates a new HtmlOutput object, and loads all the html content of the file into the final html page result. So, in this case, it takes the ‘Stylesheet.html‘ and ‘Javascript.html‘ files, and loads all their content into the final served page

<!DOCTYPE html>
<html>
<head>
<base target=”_top”>

[All the Stylesheet.html content]
var folderId = ‘root’;

[All the JavaScript.html content]

</head>


</html>

If you wish, you can add more files, to make your application more modular. For instance, if you have to add a jQuery-UI custom library, you can add the file to the project :

gapi1

and then, insert this code into the header of the main page :

<?!= HtmlService.createHtmlOutputFromFile(‘jquery_ui’).getContent(); ?>

Bind Google Scripts with Javascript.

Now that we have the static page, let’s see the dinamic part.
Opening the «JavaScript.html» file, we can find this:

gapi2

First of all, we can realize that we’re going to work with a jQuery framework, therefore there is a library link at the top.

Then, we can see the $(function() {}) declaration. As you may know, this is the way (or one of them) to implement the short document onready function in jQuery. That means that it will be executed when the page is loaded in the browser.

So, when our page is loaded in the browser, this javascript will call automaticaly the “google.script.run” method, that binds the javascript client side code with de Google Script in the server.

In order to use this method, we must to declare :

  • getFolderContents: The “Script” function to be called (into the Code.gs file). In this case, we’re going to call the getFolderContents() script function.
  • withSuccesHandler: This is the handler function that will be called after the script function, if all goes ok.
  • withFailureHandler: This is the handler function that will be called after the macro function, if anything goes wrong.

As you can see, if the macro function goes wrong, we’ll load and show the error message into the “error-message” div, giving the apropiate style to it.

Before understanding the succes handler, we must to see how the Google Script.

So, let’s open the Code.gs file again, and look to the getFolderContents() function :

gapi2

This is an easy example about how can we deal with Google Services there. In this case, it is using the Drive App Service, that allows us to work with the Google Drive.

The script gets an initial folder. If we have passed the ID parameter, it uses getFolderById() function, else the getRootFolder() function. Then, it gets the folder file list (with getFiles) and loops its 20 first files, and gets the name of each one (with getName). It loads the list into an array object (contents.children), and returns the object.

Now, into the Javascript client side, if the macro ended ok, the updateDisplay function will be executed.

gapi2

This function collect the result array into the contents parameter, and loads the list into the page with a simple loop and some dynamic html construction.

Developing a new version

Now that we have seen how the script works, we’re going to add some new code to the example, in order to understand it a little bit better.

For example, we will add a button to create a new folder. This is not complicated.

First, we add a submit input into the HTML main page :

<input type=”submit” id=”id_add_folder_button” value=”ADD NEW FOLDER”/>

and in our init javascript function, we link a function to call when it’s clicked:

$(function() {
    $(‘#id_add_folder_button’).click(fun_add_folder);
    …
}

In the fun_add_folder javascript function, we have to call a new Google Script (addFolder) :

function fun_add_folder() {
    var fname = prompt(“Folder name:”, “New folder”);
    if ((fname != null) && (fname != ”)) {
       $(‘#id_add_folder_button’).attr(‘disabled’, ‘true’);
       google.script.run
          .withSuccessHandler(function() {
             $(‘#id_add_folder_button’).removeAttr(‘disabled’)
          })
          .withFailureHandler(function(msg) {
             $(‘#error-message’).text(msg).addClass(“error”).show();
$(‘#id_add_folder_button’).removeAttr(‘disabled’)
          })
          .addFolder(folderId, fname);
    }
}

In order to avoid parallel requests, note that just after calling the function, the button turns disabled, and after executing the Google Script it turns on again. This is not the best way to prevent multiple calls at the same time, but it is helpful show the user that he shouldn’t click again the button until the answer.

In the Code.gs file, we must code the addFolder function as :

function addFolder(folderId, folder_name) {
    if (folderId == ‘root’) Current_Folder = DriveApp.getRootFolder();
    else                    Current_Folder = DriveApp.getFolderById(folderId);
    Current_Folder.createFolder(folder_name);
}

In this case, we have 2 input parameters (the folder parent ID, and the new folder name), and none for return.

We can create a new folder as easily as with calling the createFolder() function.

Now, we can try our new version with launching the /dev URL. However, this must be a provisional URL, to try the App while we’re developing. If we try to use the /exec URL, we will not see the changes, because before that, we must publish the new version of the Web App.

To get it, we must go to “Publish” – “Deploy as web app…”, and then choose a “New” Project version. It is advised to write a comment about the changes.

gapi2

And finally, updating the project version we can use the /exec URL as well.

Categories:Uncategorized
Enfilant el camí

Visualitzant el present per construir el futur

El Noguer

Visualitzant el present per construir el futur

Visualitzant el present per construir el futur