Integrating with Google Contacts

Combining several of the new features of the Tradeshift App platform, it is now possible to write an app that can synchronize your Google contacts into Tradeshift! In this blog post, I'll walk through the necessary components for this app. You can find the app on our Github repository.

If you'd like to deploy the app yourself, make sure that you replace ALL occurrences of the app's vendor ID with your own (including in the Javascript sources). You'll also need to define a Request Key with name "anonymous" and consumer secret "anonymous".

App Overview

The integration app consists of the following components:

  • A Request Key, which holds the OAuth consumer key and consumer secret to communicate with Google's API.
  • A single App Component, which lives on its own Tradeshift URL when activated. The URL is /app/JansTestCompany.GoogleAddressbook, in which 'JansTestCompany' is the vendor ID that deploys the app.
  • A pair of App Storage entries hold the OAuth token and token secret for Google's API, which identify the user's Google account.
When running, by opening the app's URL after activating it, the app roughly follows the following process:
  1. Check if there's an OAuth token in storage already. If so, try to use it on Google.
    1. If it works, retrieve the contacts and show them for import.
    2. If it doesn't work, just continue.
  2. Call Google's API to get an access token.
  3. Present a "SETUP" link, which the user can click to validate the access token at Google.
  4. User clicks the SETUP link, confirms his Google account,and gets redirected back to the app page (but with an extra oauth_verifier query parameter appended).
  5. Call Google's API to swap out the access token and verifier for a request token.
  6. Put the request token in storage, and try step (1) again.

Manifest structure

The application manifest has the several entries of relevance. It indicates that it want to use the Tradeshift API from Javascript, specifically using the network features:
"capabilities":{
		"access":["network_view",
			"network_create",
			"network_delete"
		]
	},
The main component defines three possible remote calls, the ability to make REST calls to Tradeshift's API, and several other library functions:
	
"activation":"/app/JansTestCompany.GoogleAddressbook",
"integration":{
	"append":"#mainframe"
},
"capabilities":{
	"remote":{
		"getRequest":{
			"requestToken":{
				"url":"https://www.google.com/accounts/OAuthGetRequestToken",
				"request_key":"anonymous"
			},
			"accessToken":{
				"url":"https://www.google.com/accounts/OAuthGetAccessToken",
				"request_key":"anonymous"
			},
			"contacts":{
				"url":"https://www.google.com/m8/feeds/contacts/default/full",
				"request_key":"anonymous"
			}
		}
	},
	"rest":{
		"getRequest":true,
		"generateGUID":true
	},
	"data":{
		"getDatasource":true
	},
	"system":{
		"alert":true
	},
	"console":{
		"log":true
	},
	"ui":{
		"href":true
	},
	"storage":{
		"getStorage":true
	}
},
Note also that this specific combination of activation / integration configures the app to live on it's own page, under the given URL.

Javascript structure

There are several functions of reference in the Javascript source:

function parseQuery (s) — Parses a query string (in the form 'foo=bar&me=too'), also URL-decoding the values as necessary. It returns a Javascript object with a String property/value for each parameter found in the string (so you can index it as normal properties).

function showSetupLink (dom, storage) — Requests a request token from Google, by sending an OAuth request, and using the result to dynamically show a "SETUP" link in the app. The user can click the link to go to Google and provide access.

function loadGoogle (dom, storage, token, secret) — Uses the OAuth request token and secret to load all contacts from the connected Google account. Note that Google's contact API returns XML only. The Tradeshift App framework uses the Badgerfish convention to represent XML as JSON Javascript objects, to they are easily (easier...) manipulated from Javascript. But, as you see in the code, there's still some plumbing involved.

function initialize(dom) — Performs app initialization. Based on what query parameters are found on the page, and what OAuth data is found in the app's storage, it will either present the SETUP link directly, or try to contact Google with our previously-saved OAuth keys.

ondata: function() — This callback is called when there is new RDF data on the page. There will be several calls to this function before the page (and its query string) is fully set up. Hence, there's a small check in there to see if indeed the page query string has made it into RDF yet.

References

Check the following pages for more in-depth documentation about the setup: