Friday, March 7, 2014

Google API

Some time ago I was building a spreadsheet in Google Drive to handle the math when creating characters for Savage Worlds.  I got really annoyed with how much of the math needed to be repeated and really made me wish I knew how to create functions in a spreadsheet.

It occurred to me that building it in a application would make the calculations much cleaner.  I'd just need a way to have it save the data somewhere online, since I'll need to access the character sheet at places other than my home computer.  Wouldn't you know it, Google has a .Net library to access it's spreadsheets!

The explanation for how to authenticate is a little cryptic I thought.  They push you toward using OAuth 2.0, but the ClientLogin style is much easier and makes more sense.  Despite that I still tackled OAuth 2.0, I have it working but there's a little of steps that I really want to write down before I forget them,

First off you need to go to the Google Developers Console and create yourself a project.  Then click on the name of the project to get into it's settings and options.  On the left pane you'll see a link named APIs & Auth, click that to expand it.  You'll then see a list of all the Google Apps and features that are available, which is a pretty big list.  For the program I'm working on I only need Google drive, so I enabled Drive API.

This is where you create the various tokens and such to allow your application to authenticate.  This will bind your application to the services under your Google account.  I'm not sure just how much damage could be done if these became public, so it's probably best to keep them hidden.  Seeing as how there are an array of tools to de-compile .Net applications this is probably easier said than done.  For now let's make the stuff work, securing it can be done later.

There should be two sections OAuth and Public API Access, we'll need a new Client Key in the OAuth section.  When you create the key you need to choose Installed Application, then Other since this isn't an app for a mobile device or Chrome.

Each Client Key has a unique ID, Secret, and Redirect URI; all of those will be needed to authenticate.  Before we can write the code to authenticate we need to collect some libraries, so download the Google Data API libraries for the environment of your choice.  Since Mono can read the average .Net library any of them should work the same, provided you can extract the necessary DLLs.

For what I'm showing here you just need Google.GData.Client.dll, Google.GData.Spreadsheets.dll, and Newtonsoft.Json.dll.  The Google DLLs all are strongly named, so you can't mix and match too much.  All of them have to be the exact version the others were compiled with, if you insert a newer version then you'll end up with an exception stating that it couldn't find a particular DLL.  Bottom line, only use the DLLs from the exact same Google API installer.

Finally everything is in place and ready for the code to get written.  Let's start with a basic form to see our output.  A couple labels and a pair of text boxes, nothing too fancy.
1:  using System;  
2:  using System.Windows.Forms;  
3:  using Google.GData.Client;  
4:  using Google.GData.Spreadsheets;  
5:    
6:  namespace GDrive {  
7:      class GDriveTest : Form {  
8:          public TextBox ctxtAuthURL, ctxtAccessCode;  
9:          public Label clblMessage, clblList;  
10:    
11:          public OAuth2Parameters cParams;  
12:    
13:          public static void Main(string[] astrArgs) {  
14:              GDriveTest myForm;  
15:    
16:              myForm = new GDriveTest();  
17:    
18:              Application.Run(myForm);  
19:          }  
20:    
21:          public GDriveTest() {  
22:              Button btnSubmit;  
23:    
24:              //Create the controls  
25:              clblMessage = new Label();  
26:              clblMessage.Height = 18;  
27:              clblMessage.Width = 300;  
28:              clblMessage.Top = 0;  
29:              clblMessage.Left = 0;  
30:    
31:              ctxtAuthURL = new TextBox();  
32:              ctxtAuthURL.Height = 18;  
33:              ctxtAuthURL.Width = 300;  
34:              ctxtAuthURL.Top = 20;  
35:              ctxtAuthURL.Left = 0;  
36:    
37:              ctxtAccessCode = new TextBox();  
38:              ctxtAccessCode.Height = 18;  
39:              ctxtAccessCode.Width = 300;  
40:              ctxtAccessCode.Top = 40;  
41:              ctxtAccessCode.Left = 0;  
42:                
43:              btnSubmit = new Button();  
44:              btnSubmit.Height = 18;  
45:              btnSubmit.Width = 50;  
46:              btnSubmit.Top = 60;  
47:              btnSubmit.Left = 0;  
48:              btnSubmit.Text = "Submit Code";  
49:              btnSubmit.Click += new EventHandler(SubmitAccessCode);  
50:    
51:              clblList = new Label();  
52:              clblList.Height = 200;  
53:              clblList.Width = 300;  
54:              clblList.Top = 80;  
55:              clblList.Left = 0;  
56:    
57:              //Position and configure the form  
58:              this.Width = 307;  
59:              this.Height = 307;  
60:              this.FormBorderStyle = FormBorderStyle.FixedSingle;  
61:    
62:              Controls.Add(clblMessage);  
63:              Controls.Add(ctxtAuthURL);  
64:              Controls.Add(ctxtAccessCode);  
65:              Controls.Add(btnSubmit);  
66:          }  
67:      }  
68:  }  

Lines 3 and 4 reference the Google namespaces.  We don't need to mention the Newtonsoft.Json DLL, it's needed by the Google code, nothing we do directly uses it.

Line 11 creates a variable that we'll need to authenticate with Google, I didn't want to have to repeat the class variables so I just stuck it in now.

The rest is pretty standard: creating controls, setting their properties, and getting the form up and running.

Now let's add in some of the authentication code.  This will all be tucked in at the end of the constructor, probably not the best place for it but it's convenient and works for a demonstration.

1:  //Create the authentication parameters  
2:  cParams = new OAuth2Parameters();  
3:    
4:  cParams.ClientId = "OMITTED.apps.googleusercontent.com";  
5:  cParams.ClientSecret = "OMITTED";  
6:  cParams.RedirectUri = "OMITTED";  
7:  cParams.Scope = "https://spreadsheets.google.com/feeds https://docs.google.com/feeds";  
8:  ctxtAuthURL.Text = OAuthUtil.CreateOAuth2AuthorizationUrl(cParams);  

On lines 4 to 6 I'm setting the values from the developer console.

One line 7 I'm specifying the scope to use, which tells Google which applications I intend to make use of.  In this case I'm going after Spreadsheets and Drive.  For some reason Google doesn't provide a full list of the scope URI's, however you can get a bunch of them here.

Lastly on line 8 I use a helper function to generate a URL for the user to follow.  What this does is take the user to a page that lets them give or deny access to the requested Google apps.  Since the authentication is bound to the Project in the Developer Console it will be tied to a specific account, so just anyone can't authorize it.

So the user needs to go to that URL and get the access code and give it to the program.  When they click the submit button the last part of the authentication will happen, all of that stuff will go in the callback function SubmitAccessCode().
1:  private void SubmitAccessCode(object oSender, EventArgs eaArgs) {  
2:      GOAuth2RequestFactory reqFactory;  
3:      SpreadsheetsService gsService;  
4:      SpreadsheetQuery sqQuery;  
5:      SpreadsheetFeed sfFeed;  
6:    
7:      cParams.AccessCode = ctxtAccessCode.Text;  
8:      OAuthUtil.GetAccessToken(cParams);  
9:    
10:      reqFactory = new GOAuth2RequestFactory(null, "", cParams);  
11:      gsService = new SpreadsheetsService("");  
12:      sqQuery = new SpreadsheetQuery();  
13:    
14:      gsService.RequestFactory = reqFactory;  
15:    
16:      sfFeed = gsService.Query(sqQuery);  
17:    
18:      clblList.Text = "";  
19:      foreach (SpreadsheetEntry seEntry in sfFeed.Entries) {  
20:          clblList.Text = clblList.Text + "\n" + seEntry.Title.Text;  
21:      }  
22:  }  

In theory the user will go to the URL in ctxtAuthURL get the authorization token and put it in ctxtAccessCode text box.  Line 7 adds it to our parameters.

Line 8 uses a Google function to build the access token from all the parameters we've set.  Finally we have access to make use of the Google web applications.

Lines 10 through 12 creates all of the variables we'll need to access spreadsheet data withing Google Drive.

Line 16 performs a query to give us a list of spreadsheets available in Google drive.  We're not setting any filters, so it should give us a list of everything in there.

Then finally we'll loop through all the returned spreadsheet names and write them to the clblList control.  This is done on lines 18 through 21.

The code is all pretty simple, most of it is just setting values in Google variables.  Most of the confusing stuff is navigating the Google Developer console.  I really wanted to have screenshots of all those web pages, but according to those same pages they are being redesigned, so not much value in the screenshots.

If you'd like to see all of the code together, go here.  Unlike all the other code this one won't run right out of the box, it'll compile just fine but I've pulled out the authentication stuff so it'll fail at some point.  It should be easy enough to generate those values to correct this though.

No comments:

Post a Comment